diff -Naurp linux-2.6.13.orig/arch/mips/Kconfig linux-2.6.13/arch/mips/Kconfig --- linux-2.6.13.orig/arch/mips/Kconfig 2005-08-30 21:46:39.000000000 -0400 +++ linux-2.6.13/arch/mips/Kconfig 2005-08-30 22:04:48.000000000 -0400 @@ -514,6 +514,25 @@ config SGI_IP27 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 @@ -929,7 +948,7 @@ config VR4181 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 @@ -938,7 +957,7 @@ config ARC_MEMORY 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 @@ -1300,6 +1319,14 @@ config 64BIT_PHYS_ADDR 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 64BIT + 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 diff -Naurp linux-2.6.13.orig/arch/mips/Makefile linux-2.6.13/arch/mips/Makefile --- linux-2.6.13.orig/arch/mips/Makefile 2005-08-30 21:46:39.000000000 -0400 +++ linux-2.6.13/arch/mips/Makefile 2005-08-30 22:04:48.000000000 -0400 @@ -633,6 +633,19 @@ endif 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, diff -Naurp linux-2.6.13.orig/arch/mips/kernel/gdb-low.S linux-2.6.13/arch/mips/kernel/gdb-low.S --- linux-2.6.13.orig/arch/mips/kernel/gdb-low.S 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/arch/mips/kernel/gdb-low.S 2005-08-30 22:04:48.000000000 -0400 @@ -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_64BIT + 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) diff -Naurp linux-2.6.13.orig/arch/mips/kernel/setup.c linux-2.6.13/arch/mips/kernel/setup.c --- linux-2.6.13.orig/arch/mips/kernel/setup.c 2005-08-30 21:46:39.000000000 -0400 +++ linux-2.6.13/arch/mips/kernel/setup.c 2005-08-30 22:04:48.000000000 -0400 @@ -370,11 +370,11 @@ static inline void bootmem_init(void) (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; @@ -392,10 +392,10 @@ static inline void resource_init(void) * 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; diff -Naurp linux-2.6.13.orig/arch/mips/lib/memcpy.S linux-2.6.13/arch/mips/lib/memcpy.S --- linux-2.6.13.orig/arch/mips/lib/memcpy.S 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/arch/mips/lib/memcpy.S 2005-08-30 22:04:48.000000000 -0400 @@ -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 @@ FEXPORT(__copy_user) */ #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 @@ both_aligned: 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 t2, UNIT(2)(src), l_exc_copy) 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 @@ less_than_4units: 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( LDFIRST t3, FIRST(0)(src), l_exc) 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 @@ src_unaligned_dst_aligned: * 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 @@ cleanup_src_unaligned: 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 @@ copy_bytes_checklen: 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 @@ LEAF(__rmemcpy) /* a0=dst a1=src a2= 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 @@ r_out: move a2, zero r_end_bytes_up: + R10KCBARRIER(0(ra)) lb t0, (a1) SUB a2, a2, 0x1 sb t0, (a0) diff -Naurp linux-2.6.13.orig/arch/mips/lib/strncpy_user.S linux-2.6.13/arch/mips/lib/strncpy_user.S --- linux-2.6.13.orig/arch/mips/lib/strncpy_user.S 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/arch/mips/lib/strncpy_user.S 2005-08-30 22:04:48.000000000 -0400 @@ -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 @@ FEXPORT(__strncpy_from_user_nocheck_asm) .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 diff -Naurp linux-2.6.13.orig/arch/mips/lib-64/memset.S linux-2.6.13/arch/mips/lib-64/memset.S --- linux-2.6.13.orig/arch/mips/lib-64/memset.S 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/arch/mips/lib-64/memset.S 2005-08-30 22:04:48.000000000 -0400 @@ -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 @@ FEXPORT(__bzero) 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 @@ FEXPORT(__bzero) 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 @@ memset_partial: 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 @@ small_memset: PTR_ADDU t1, a0, a2 1: PTR_ADDIU a0, 1 /* fill bytewise */ + R10KCBARRIER(0(ra)) bne t1, a0, 1b sb a1, -1(a0) diff -Naurp linux-2.6.13.orig/arch/mips/mm/c-r4k.c linux-2.6.13/arch/mips/mm/c-r4k.c --- linux-2.6.13.orig/arch/mips/mm/c-r4k.c 2005-08-30 21:46:39.000000000 -0400 +++ linux-2.6.13/arch/mips/mm/c-r4k.c 2005-08-30 22:04:48.000000000 -0400 @@ -667,6 +667,27 @@ static void r4k_dma_cache_inv(unsigned l 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 */ /* @@ -1220,7 +1241,16 @@ void __init ld_mmu_r4xx0(void) #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(); diff -Naurp linux-2.6.13.orig/arch/mips/mm/init.c linux-2.6.13/arch/mips/mm/init.c --- linux-2.6.13.orig/arch/mips/mm/init.c 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/arch/mips/mm/init.c 2005-08-30 22:04:48.000000000 -0400 @@ -225,6 +225,7 @@ void __init mem_init(void) if (PageReserved(mem_map+tmp)) reservedpages++; } + num_physpages = ram; #ifdef CONFIG_HIGHMEM for (tmp = highstart_pfn; tmp < highend_pfn; tmp++) { @@ -241,6 +242,7 @@ void __init mem_init(void) set_page_count(page, 1); __free_page(page); totalhigh_pages++; + ++num_physpages; } totalram_pages += totalhigh_pages; #endif @@ -266,8 +268,8 @@ void free_initrd_mem(unsigned long start { #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 @@ void free_initmem(void) 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 diff -Naurp linux-2.6.13.orig/arch/mips/sgi-ip22/Makefile linux-2.6.13/arch/mips/sgi-ip22/Makefile --- linux-2.6.13.orig/arch/mips/sgi-ip22/Makefile 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/arch/mips/sgi-ip22/Makefile 2005-08-30 22:04:48.000000000 -0400 @@ -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 -Naurp linux-2.6.13.orig/arch/mips/sgi-ip22/ip22-mc.c linux-2.6.13/arch/mips/sgi-ip22/ip22-mc.c --- linux-2.6.13.orig/arch/mips/sgi-ip22/ip22-mc.c 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/arch/mips/sgi-ip22/ip22-mc.c 2005-08-30 22:04:48.000000000 -0400 @@ -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 @@ void __init sgimc_init(void) 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 @@ void __init sgimc_init(void) * 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 @@ void __init sgimc_init(void) */ 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 @@ void __init sgimc_init(void) * 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 @@ void __init sgimc_init(void) 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 @@ void __init sgimc_init(void) 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 @@ unsigned long __init prom_free_prom_memo { 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 -Naurp linux-2.6.13.orig/arch/mips/sgi-ip22/ip22-setup.c linux-2.6.13/arch/mips/sgi-ip22/ip22-setup.c --- linux-2.6.13.orig/arch/mips/sgi-ip22/ip22-setup.c 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/arch/mips/sgi-ip22/ip22-setup.c 2005-08-30 22:04:48.000000000 -0400 @@ -125,6 +125,34 @@ void __init plat_setup(void) } } #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 -Naurp linux-2.6.13.orig/arch/mips/sgi-ip22/ip28-berr.c linux-2.6.13/arch/mips/sgi-ip22/ip28-berr.c --- linux-2.6.13.orig/arch/mips/sgi-ip22/ip28-berr.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.13/arch/mips/sgi-ip22/ip28-berr.c 2005-08-30 22:04:48.000000000 -0400 @@ -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 -Naurp linux-2.6.13.orig/drivers/char/Kconfig linux-2.6.13/drivers/char/Kconfig --- linux-2.6.13.orig/drivers/char/Kconfig 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/drivers/char/Kconfig 2005-08-30 22:04:48.000000000 -0400 @@ -762,7 +762,7 @@ config RTC 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 -Naurp linux-2.6.13.orig/drivers/char/tty_io.c linux-2.6.13/drivers/char/tty_io.c --- linux-2.6.13.orig/drivers/char/tty_io.c 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/drivers/char/tty_io.c 2005-08-30 22:04:48.000000000 -0400 @@ -716,6 +716,7 @@ static struct file *redirect; void tty_wakeup(struct tty_struct *tty) { + if (tty) { struct tty_ldisc *ld; if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { @@ -727,6 +728,7 @@ void tty_wakeup(struct tty_struct *tty) } } wake_up_interruptible(&tty->write_wait); + } } EXPORT_SYMBOL_GPL(tty_wakeup); diff -Naurp linux-2.6.13.orig/drivers/char/watchdog/Kconfig linux-2.6.13/drivers/char/watchdog/Kconfig --- linux-2.6.13.orig/drivers/char/watchdog/Kconfig 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/drivers/char/watchdog/Kconfig 2005-08-30 22:04:48.000000000 -0400 @@ -350,7 +350,7 @@ config 8xx_WDT 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 -Naurp linux-2.6.13.orig/drivers/input/serio/i8042.c linux-2.6.13/drivers/input/serio/i8042.c --- linux-2.6.13.orig/drivers/input/serio/i8042.c 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/drivers/input/serio/i8042.c 2005-08-30 22:04:48.000000000 -0400 @@ -652,7 +652,13 @@ static int __init i8042_check_aux(void) 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 -Naurp linux-2.6.13.orig/drivers/input/serio/i8042.h linux-2.6.13/drivers/input/serio/i8042.h --- linux-2.6.13.orig/drivers/input/serio/i8042.h 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/drivers/input/serio/i8042.h 2005-08-30 22:04:48.000000000 -0400 @@ -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" diff -Naurp linux-2.6.13.orig/drivers/net/Kconfig linux-2.6.13/drivers/net/Kconfig --- linux-2.6.13.orig/drivers/net/Kconfig 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/drivers/net/Kconfig 2005-08-30 22:04:48.000000000 -0400 @@ -1718,7 +1718,7 @@ config DE620 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 -Naurp linux-2.6.13.orig/drivers/net/sgiseeq.c linux-2.6.13/drivers/net/sgiseeq.c --- linux-2.6.13.orig/drivers/net/sgiseeq.c 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/drivers/net/sgiseeq.c 2005-08-30 21:59:38.000000000 -0400 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,34 @@ static char *version = "sgiseeq.c: David static char *sgiseeqstr = "SGI Seeq8003"; +#if defined(CONFIG_SGI_IP28) || defined(CONFIG_SGI_IP26) +/* see SGI documents: 007-0911-210, Chapter I.1. and man ip26_ucmem(D3) */ +# define DMA_NONCOHERENT_CODE(code...) code +/* (Extra) code to handle stores to uncached memory on these systems */ +# define IP28_IP26_CODE(code...) code +#else +# if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_NONCOHERENT_IO) +# define DMA_NONCOHERENT_CODE(code...) code +# else +# define DMA_NONCOHERENT_CODE(code...) +# endif +# define IP28_IP26_CODE(code...) +#endif + +#ifdef TO_PHYS /* mach-ip28/spaces.h, mach-ip22/spaces.h/MIPS64, ... */ +# define SEEQCAC(p) TO_CAC( (unsigned long)(p)) +# define SEEQUNCAC(p) TO_UNCAC((unsigned long)(p)) +# define SEEQPHYS(p) TO_PHYS((unsigned long)(p)) +#else /* mach-ip22/spaces.h/MIPS32, ... */ +# define SEEQCAC(p) CKSEG0ADDR(p) +# define SEEQUNCAC(p) CKSEG1ADDR(p) +# define SEEQPHYS(p) CPHYSADDR(p) +#endif + +/* Alignment to the largest IP2X cacheblock. */ +#define CACHLIGNDN(x) ((x) & ~0x7f) +#define CACHLIGNUP(x) CACHLIGNDN((x)+0x7f) + /* * If you want speed, you do something silly, it always has worked for me. So, * with that in mind, I've decided to make this driver look completely like a @@ -45,8 +74,11 @@ static char *sgiseeqstr = "SGI Seeq8003" * how a stupid idea like this can pay off in performance, not to mention * making this driver 2,000 times easier to write. ;-) */ - -/* Tune these if we tend to run out often etc. */ +/* + * Tune these if we tend to run out often etc. + * But please don't break the follwing NEXT/PREV macros (i.e. use 16*2^N) + * Btw: doing so, keeps both arrays cacheline-aligned too ;-) + */ #define SEEQ_RX_BUFFERS 16 #define SEEQ_TX_BUFFERS 16 @@ -65,17 +97,19 @@ static char *sgiseeqstr = "SGI Seeq8003" struct sgiseeq_rx_desc { volatile struct hpc_dma_desc rdma; - volatile signed int buf_vaddr; + int _padding[3]; + unsigned long buf_vaddr; }; struct sgiseeq_tx_desc { volatile struct hpc_dma_desc tdma; - volatile signed int buf_vaddr; + int _padding[3]; + unsigned long buf_vaddr; }; /* * Warning: This structure is layed out in a certain way because HPC dma - * descriptors must be 8-byte aligned. So don't touch this without + * descriptors must be 16-byte aligned. So don't touch this without * some care. */ struct sgiseeq_init_block { /* Note the name ;-) */ @@ -111,6 +145,7 @@ struct sgiseeq_private { /* A list of all installed seeq devices, for removing the driver module. */ static struct net_device *root_sgiseeq_dev; + static inline void hpc3_eth_reset(struct hpc3_ethregs *hregs) { hregs->rx_reset = HPC3_ERXRST_CRESET | HPC3_ERXRST_CLRIRQ; @@ -168,6 +203,8 @@ static int sgiseeq_set_mac_address(struc static int seeq_init_ring(struct net_device *dev) { struct sgiseeq_private *sp = netdev_priv(dev); + struct sgiseeq_tx_desc *td; + struct sgiseeq_rx_desc *rd; int i; netif_stop_queue(dev); @@ -177,33 +214,60 @@ static int seeq_init_ring(struct net_dev __sgiseeq_set_mac_address(dev); /* Setup tx ring. */ + td = sp->tx_desc; + IP28_IP26_CODE( + /* Here it's best to avoid uncached writes altogether. */ + td = (typeof(td)) SEEQCAC(td); + ) for(i = 0; i < SEEQ_TX_BUFFERS; i++) { - if (!sp->tx_desc[i].tdma.pbuf) { + if (!td[i].tdma.pbuf) { unsigned long buffer; - buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); + /* Align buffer (start and size) to largest cacheblock. */ + buffer = (unsigned long) + kmalloc(CACHLIGNUP(PKT_BUF_SZ), GFP_KERNEL); if (!buffer) return -ENOMEM; - sp->tx_desc[i].buf_vaddr = CKSEG1ADDR(buffer); - sp->tx_desc[i].tdma.pbuf = CPHYSADDR(buffer); + DMA_NONCOHERENT_CODE( + dma_cache_inv(buffer,PKT_BUF_SZ); + ) + td[i].buf_vaddr = SEEQUNCAC(buffer); + td[i].tdma.pbuf = SEEQPHYS(buffer); } - sp->tx_desc[i].tdma.cntinfo = TCNTINFO_INIT; + td[i].tdma.cntinfo = TCNTINFO_INIT; } - + IP28_IP26_CODE( + dma_cache_wback_inv((unsigned long)sp->srings->txvector, + sizeof(sp->srings->txvector)); + ) /* And now the rx ring. */ + rd = sp->rx_desc; + IP28_IP26_CODE( + /* Here it's best to avoid uncached writes altogether. */ + rd = (typeof(rd)) SEEQCAC(rd); + ) for (i = 0; i < SEEQ_RX_BUFFERS; i++) { - if (!sp->rx_desc[i].rdma.pbuf) { + if (!rd[i].rdma.pbuf) { unsigned long buffer; - buffer = (unsigned long) kmalloc(PKT_BUF_SZ, GFP_KERNEL); + /* Align buffer (start and size) to largest cacheblock. */ + buffer = (unsigned long) + kmalloc(CACHLIGNUP(PKT_BUF_SZ), GFP_KERNEL); if (!buffer) return -ENOMEM; - sp->rx_desc[i].buf_vaddr = CKSEG1ADDR(buffer); - sp->rx_desc[i].rdma.pbuf = CPHYSADDR(buffer); + DMA_NONCOHERENT_CODE( + dma_cache_inv(buffer,PKT_BUF_SZ); + ) + rd[i].buf_vaddr = SEEQUNCAC(buffer); + rd[i].rdma.pbuf = SEEQPHYS(buffer); } - sp->rx_desc[i].rdma.cntinfo = RCNTINFO_INIT; + rd[i].rdma.cntinfo = RCNTINFO_INIT; } - sp->rx_desc[i - 1].rdma.cntinfo |= HPCDMA_EOR; + rd[i - 1].rdma.cntinfo |= HPCDMA_EOR; + IP28_IP26_CODE( + dma_cache_wback_inv((unsigned long)sp->srings->rxvector, + sizeof(sp->srings->rxvector)); + ) return 0; } @@ -276,8 +340,8 @@ static int init_seeq(struct net_device * hregs->rx_dconfig |= RDMACFG_INIT; - hregs->rx_ndptr = CPHYSADDR(sp->rx_desc); - hregs->tx_ndptr = CPHYSADDR(sp->tx_desc); + hregs->rx_ndptr = SEEQPHYS(sp->rx_desc); + hregs->tx_ndptr = SEEQPHYS(sp->tx_desc); seeq_go(sp, hregs, sregs); return 0; @@ -302,7 +366,7 @@ static inline void rx_maybe_restart(stru struct sgiseeq_regs *sregs) { if (!(hregs->rx_ctrl & HPC3_ERXCTRL_ACTIVE)) { - hregs->rx_ndptr = CPHYSADDR(sp->rx_desc + sp->rx_new); + hregs->rx_ndptr = SEEQPHYS(sp->rx_desc + sp->rx_new); seeq_go(sp, hregs, sregs); } } @@ -316,21 +380,22 @@ static inline void sgiseeq_rx(struct net struct sgiseeq_regs *sregs) { struct sgiseeq_rx_desc *rd; - struct sk_buff *skb = 0; - unsigned char pkt_status; - unsigned char *pkt_pointer = 0; - int len = 0; unsigned int orig_end = PREV_RX(sp->rx_new); - + + IP28_IP26_CODE( + unsigned long ucmemstat = ip2628_enable_ucmem(); + ) /* Service every received packet. */ for_each_rx(rd, sp) { - len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3; + unsigned char pkt_status; + const unsigned char *pkt_pointer; + int len = PKT_BUF_SZ - (rd->rdma.cntinfo & HPCDMA_BCNT) - 3; pkt_pointer = (unsigned char *)(long)rd->buf_vaddr; pkt_status = pkt_pointer[len + 2]; - if (pkt_status & SEEQ_RSTAT_FIG) { + if (len > 0 && (pkt_status & SEEQ_RSTAT_FIG)) { /* Packet is OK. */ - skb = dev_alloc_skb(len + 2); + struct sk_buff *skb = dev_alloc_skb(len + 2); if (skb) { skb->dev = dev; @@ -364,8 +429,11 @@ static inline void sgiseeq_rx(struct net rd->rdma.cntinfo = RCNTINFO_INIT; sp->rx_new = NEXT_RX(sp->rx_new); } - sp->rx_desc[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR); - sp->rx_desc[PREV_RX(sp->rx_new)].rdma.cntinfo |= HPCDMA_EOR; + rd = sp->rx_desc; + rd[orig_end].rdma.cntinfo &= ~(HPCDMA_EOR); + rd[PREV_RX(sp->rx_new)].rdma.cntinfo |= HPCDMA_EOR; + + IP28_IP26_CODE( ip2628_return_ucmem(ucmemstat); ) rx_maybe_restart(sp, hregs, sregs); } @@ -378,7 +446,7 @@ static inline void tx_maybe_reset_collis } } -static inline void kick_tx(struct sgiseeq_tx_desc *td, +static inline void kick_tx(const volatile struct sgiseeq_tx_desc *td, struct hpc3_ethregs *hregs) { /* If the HPC aint doin nothin, and there are more packets @@ -389,9 +457,9 @@ static inline void kick_tx(struct sgisee */ while ((td->tdma.cntinfo & (HPCDMA_XIU | HPCDMA_ETXD)) == (HPCDMA_XIU | HPCDMA_ETXD)) - td = (struct sgiseeq_tx_desc *)(long) CKSEG1ADDR(td->tdma.pnext); + td = (typeof(td))(long) SEEQUNCAC(td->tdma.pnext); if (td->tdma.cntinfo & HPCDMA_XIU) { - hregs->tx_ndptr = CPHYSADDR(td); + hregs->tx_ndptr = SEEQPHYS(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } } @@ -403,6 +471,7 @@ static inline void sgiseeq_tx(struct net struct sgiseeq_tx_desc *td; unsigned long status = hregs->tx_ctrl; int j; + IP28_IP26_CODE( unsigned long ucmemstat; ) tx_maybe_reset_collisions(sp, sregs); @@ -416,6 +485,7 @@ static inline void sgiseeq_tx(struct net sp->stats.collisions++; } + IP28_IP26_CODE( ucmemstat = ip2628_enable_ucmem(); ) /* Ack 'em... */ for (j = sp->tx_old; j != sp->tx_new; j = NEXT_TX(j)) { td = &sp->tx_desc[j]; @@ -424,7 +494,7 @@ static inline void sgiseeq_tx(struct net break; if (!(td->tdma.cntinfo & (HPCDMA_ETXD))) { if (!(status & HPC3_ETXCTRL_ACTIVE)) { - hregs->tx_ndptr = CPHYSADDR(td); + hregs->tx_ndptr = SEEQPHYS(td); hregs->tx_ctrl = HPC3_ETXCTRL_ACTIVE; } break; @@ -434,6 +504,7 @@ static inline void sgiseeq_tx(struct net td->tdma.cntinfo &= ~(HPCDMA_XIU | HPCDMA_XIE); td->tdma.cntinfo |= HPCDMA_EOX; } + IP28_IP26_CODE( ip2628_return_ucmem(ucmemstat); ) } static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs) @@ -462,6 +533,14 @@ static irqreturn_t sgiseeq_interrupt(int return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +static void sgiseeq_poll(struct net_device *dev) +{ + disable_irq(dev->irq); + sgiseeq_interrupt(dev->irq, dev, NULL); + enable_irq(dev->irq); +} +#endif static int sgiseeq_open(struct net_device *dev) { @@ -533,6 +612,8 @@ static int sgiseeq_start_xmit(struct sk_ unsigned long flags; struct sgiseeq_tx_desc *td; int skblen, len, entry; + char *vbuf; + IP28_IP26_CODE( unsigned long ucmemstat; ) spin_lock_irqsave(&sp->tx_lock, flags); @@ -556,9 +637,15 @@ static int sgiseeq_start_xmit(struct sk_ * entry and the HPC got to the end of the chain before we * added this new entry and restarted it. */ - memcpy((char *)(long)td->buf_vaddr, skb->data, skblen); + vbuf = (char *)(long)td->buf_vaddr; + IP28_IP26_CODE( vbuf = (typeof(vbuf)) SEEQCAC(vbuf); ) + memcpy(vbuf, skb->data, skblen); if (len != skblen) - memset((char *)(long)td->buf_vaddr + skb->len, 0, len-skblen); + memset(vbuf + skb->len, 0, len-skblen); + IP28_IP26_CODE( + dma_cache_wback_inv((unsigned long)vbuf, len); + ucmemstat = ip2628_enable_ucmem(); + ) td->tdma.cntinfo = (len & HPCDMA_BCNT) | HPCDMA_XIU | HPCDMA_EOXP | HPCDMA_XIE | HPCDMA_EOX; if (sp->tx_old != sp->tx_new) { @@ -567,6 +654,7 @@ static int sgiseeq_start_xmit(struct sk_ backend = &sp->tx_desc[PREV_TX(sp->tx_new)]; backend->tdma.cntinfo &= ~HPCDMA_EOX; } + IP28_IP26_CODE( ip2628_return_ucmem(ucmemstat); ) sp->tx_new = NEXT_TX(sp->tx_new); /* Advance. */ /* Maybe kick the HPC back into motion. */ @@ -624,11 +712,11 @@ static inline void setup_tx_ring(struct int i = 0; while (i < (nbufs - 1)) { - buf[i].tdma.pnext = CPHYSADDR(buf + i + 1); + buf[i].tdma.pnext = SEEQPHYS(buf + i + 1); buf[i].tdma.pbuf = 0; i++; } - buf[i].tdma.pnext = CPHYSADDR(buf); + buf[i].tdma.pnext = SEEQPHYS(buf); } static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) @@ -636,12 +724,12 @@ static inline void setup_rx_ring(struct int i = 0; while (i < (nbufs - 1)) { - buf[i].rdma.pnext = CPHYSADDR(buf + i + 1); + buf[i].rdma.pnext = SEEQPHYS(buf + i + 1); buf[i].rdma.pbuf = 0; i++; } buf[i].rdma.pbuf = 0; - buf[i].rdma.pnext = CPHYSADDR(buf); + buf[i].rdma.pnext = SEEQPHYS(buf); } #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) @@ -653,6 +741,23 @@ static int sgiseeq_init(struct hpc3_regs struct net_device *dev; int err, i; + if (ALIGNED(sizeof(*sr->rxvector)) != sizeof(*sr->rxvector) || + ALIGNED(sizeof(*sr->txvector)) != sizeof(*sr->txvector) || + ALIGNED(offsetof(typeof(*sr), rxvector)) + != offsetof(typeof(*sr), rxvector) || + ALIGNED(offsetof(typeof(*sr), txvector)) + != offsetof(typeof(*sr), txvector)) { + printk(KERN_ERR "Sgiseeq: FIXME: HPC dma descriptors " + "must be %d-byte aligned.\n", ALIGNED(1)); + err = -ENOMEM; + goto err_out; + } + if (PAGE_SIZE < sizeof(*sr)) { + printk(KERN_ERR "Sgiseeq: FIXME: Too many dma descriptors " + "to fit in page.\n"); + err = -ENOMEM; + goto err_out; + } dev = alloc_etherdev(sizeof (struct sgiseeq_private)); if (!dev) { printk(KERN_ERR "Sgiseeq: Etherdev alloc failed, aborting.\n"); @@ -687,18 +792,15 @@ static int sgiseeq_init(struct hpc3_regs sp->name = sgiseeqstr; sp->mode = SEEQ_RCMD_RBCAST; - sp->rx_desc = (struct sgiseeq_rx_desc *) - CKSEG1ADDR(ALIGNED(&sp->srings->rxvector[0])); - dma_cache_wback_inv((unsigned long)&sp->srings->rxvector, - sizeof(sp->srings->rxvector)); - sp->tx_desc = (struct sgiseeq_tx_desc *) - CKSEG1ADDR(ALIGNED(&sp->srings->txvector[0])); - dma_cache_wback_inv((unsigned long)&sp->srings->txvector, - sizeof(sp->srings->txvector)); + sp->rx_desc = (typeof(sp->rx_desc)) SEEQUNCAC(&sr->rxvector[0]); + sp->tx_desc = (typeof(sp->tx_desc)) SEEQUNCAC(&sr->txvector[0]); /* A couple calculations now, saves many cycles later. */ - setup_rx_ring(sp->rx_desc, SEEQ_RX_BUFFERS); - setup_tx_ring(sp->tx_desc, SEEQ_TX_BUFFERS); + setup_rx_ring(sr->rxvector, SEEQ_RX_BUFFERS); + setup_tx_ring(sr->txvector, SEEQ_TX_BUFFERS); + + dma_cache_wback_inv((unsigned long)&sr->rxvector, sizeof(sr->rxvector)); + dma_cache_wback_inv((unsigned long)&sr->txvector, sizeof(sr->txvector)); /* Reset the chip. */ hpc3_eth_reset(sp->hregs); @@ -718,6 +820,9 @@ static int sgiseeq_init(struct hpc3_regs dev->set_multicast_list = sgiseeq_set_multicast; dev->set_mac_address = sgiseeq_set_mac_address; dev->irq = irq; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = sgiseeq_poll; +#endif if (register_netdev(dev)) { printk(KERN_ERR "Sgiseeq: Cannot register net device, " @@ -736,7 +841,7 @@ static int sgiseeq_init(struct hpc3_regs return 0; err_out_free_page: - free_page((unsigned long) sp->srings); + free_page((unsigned long) sr); err_out_free_dev: kfree(dev); @@ -770,3 +875,11 @@ module_init(sgiseeq_probe); module_exit(sgiseeq_exit); MODULE_LICENSE("GPL"); +/* + * 2.4.22 Sun Sep 21 05:32:42 2003 + * 2.4.x Revision 1.31.2.14, Sat Jul 31 01:47:15 2004 + * 2.6.x Revision 1.67, Tue Apr 12 16:00:58 2005 + * + * Jun/Dec 2004, Apr 2005 peter fuerst (pf@net.alphadv.de) + * - xkphys, cache-alignment, IP28/IP26 + */ diff -Naurp linux-2.6.13.orig/drivers/scsi/Kconfig linux-2.6.13/drivers/scsi/Kconfig --- linux-2.6.13.orig/drivers/scsi/Kconfig 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/drivers/scsi/Kconfig 2005-08-30 22:04:48.000000000 -0400 @@ -236,7 +236,7 @@ menu "SCSI low-level drivers" 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 -Naurp linux-2.6.13.orig/drivers/scsi/sgiwd93.c linux-2.6.13/drivers/scsi/sgiwd93.c --- linux-2.6.13.orig/drivers/scsi/sgiwd93.c 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/drivers/scsi/sgiwd93.c 2005-08-30 21:59:41.000000000 -0400 @@ -7,6 +7,7 @@ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu) * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org) * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org) + * Copyright (C) 2004 Peter Fuerst (pf@net.alphadv.de) - IP28 * * (In all truth, Jed Schimmel wrote all this code.) */ @@ -42,6 +43,33 @@ #define DPRINTK(args...) #endif +#if defined(CONFIG_SGI_IP28) || defined(CONFIG_SGI_IP26) +/* see SGI documents: 007-0911-210, Chapter I.1. and man ip26_ucmem(D3) */ +# define DMA_NONCOHERENT_CODE(code...) code +# define IP28_IP26_CODE(code...) code /* avoid uncached writes */ +#else +# if defined(CONFIG_DMA_NONCOHERENT) || defined(CONFIG_NONCOHERENT_IO) +# define DMA_NONCOHERENT_CODE(code...) code +# else +# define DMA_NONCOHERENT_CODE(code...) +# endif +# define IP28_IP26_CODE(code...) +#endif + +#ifdef TO_PHYS /* mach-ip28/spaces.h, mach-ip22/spaces.h/MIPS64, ... */ +# define WD93CAC(p) TO_CAC( (unsigned long)(p)) +# define WD93UNCAC(p) TO_UNCAC((unsigned long)(p)) +# define WD93PHYS(p) TO_PHYS((unsigned long)(p)) +#else /* mach-ip22/spaces.h/MIPS32, ... */ +# define WD93CAC(p) CKSEG0ADDR(p) +# define WD93UNCAC(p) CKSEG1ADDR(p) +# define WD93PHYS(p) CPHYSADDR(p) +#endif + +/* Alignment to the largest IP2X cacheblock. */ +#define CACHLIGNDN(x) ((x) & ~0x7f) +#define CACHLIGNUP(x) CACHLIGNDN((x)+0x7f) + #define HDATA(ptr) ((struct ip22_hostdata *)((ptr)->hostdata)) struct ip22_hostdata { @@ -49,6 +77,16 @@ struct ip22_hostdata { struct hpc_data { dma_addr_t dma; void * cpu; + /* + * A cacheline-aligned intermediate dma read buffer for all + * the small, not cacheline-aligned Scsi_Cmnd input buffers. + */ + char (*buf)[PAGE_SIZE]; + struct { + char *scp; + char *rbp; + unsigned len; + } rb; } hd; }; @@ -57,6 +95,9 @@ struct hpc_chunk { u32 _padding; /* align to quadword boundary */ }; +static dma_addr_t sgiwd93_dma_map(Scsi_Cmnd*); +static void sgiwd93_dma_unmap(Scsi_Cmnd*); + struct Scsi_Host *sgiwd93_host; struct Scsi_Host *sgiwd93_host1; @@ -98,20 +139,29 @@ static irqreturn_t sgiwd93_intr(int irq, } static inline -void fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd, int datainp) +int fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd) { unsigned long len = cmd->SCp.this_residual; - void *addr = cmd->SCp.ptr; dma_addr_t physaddr; unsigned long count; - - physaddr = dma_map_single(NULL, addr, len, cmd->sc_data_direction); - cmd->SCp.dma_handle = physaddr; - + IP28_IP26_CODE( int nc; struct hpc_chunk *hcpstart; ) + + physaddr = sgiwd93_dma_map(cmd); + if (!physaddr) + return 1; + + IP28_IP26_CODE( + hcpstart = hcp = (typeof(hcp)) WD93CAC(hcp); + nc = 1 + (len + 8191) / 8192; + nc = CACHLIGNUP(sizeof(*hcp)*nc); + /* dma_cache_inv((unsigned long) hcp, nc); */ + ) while (len) { /* * even cntinfo could be up to 16383, without * magic only 8192 works correctly + * (even much less than 8192 may fail, since + * pbuf must not cross any page boundaries !) */ count = len > 8192 ? 8192 : len; hcp->desc.pbuf = physaddr; @@ -128,6 +178,9 @@ void fill_hpc_entries(struct hpc_chunk * */ hcp->desc.pbuf = 0; hcp->desc.cntinfo = HPCDMA_EOX; + + IP28_IP26_CODE( dma_cache_wback_inv((unsigned long)hcpstart, nc); ) + return 0; } static int dma_setup(Scsi_Cmnd *cmd, int datainp) @@ -139,6 +192,11 @@ static int dma_setup(Scsi_Cmnd *cmd, int DPRINTK("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp); + if (datainp && cmd->sc_data_direction != DMA_FROM_DEVICE || + !datainp && cmd->sc_data_direction != DMA_TO_DEVICE) + DPRINTK(KERN_WARNING "sgiwd93: DMA direction mismatch: " + "data %sput vs. sc_data_direction %d !\n", + datainp ? "in":"out", cmd->sc_data_direction); hdata->wh.dma_dir = datainp; /* @@ -147,11 +205,14 @@ static int dma_setup(Scsi_Cmnd *cmd, int * obvious). IMHO a better fix would be, not to do these dma setups * in the first place. */ - if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0) + if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0) { + DPRINTK("\n"); return 1; - - fill_hpc_entries(hcp, cmd, datainp); - + } + if (fill_hpc_entries(hcp, cmd)) { + DPRINTK("\n"); + return 1; + } DPRINTK(" HPCGO\n"); /* Start up the HPC. */ @@ -171,7 +232,7 @@ static void dma_stop(struct Scsi_Host *i struct hpc3_scsiregs *hregs; if (!SCpnt) - return; + return; /* really ignore wd33c93_host_reset() ? */ hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base; @@ -184,8 +245,7 @@ static void dma_stop(struct Scsi_Host *i barrier(); } hregs->ctrl = 0; - dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual, - SCpnt->sc_data_direction); + sgiwd93_dma_unmap(SCpnt); DPRINTK("\n"); } @@ -204,17 +264,24 @@ static inline void init_hpc_chain(struct struct hpc_chunk *hcp = (struct hpc_chunk *) hd->cpu; struct hpc_chunk *dma = (struct hpc_chunk *) hd->dma; unsigned long start, end; - + + IP28_IP26_CODE( hcp = (typeof(hcp)) WD93CAC(hcp); ) start = (unsigned long) hcp; end = start + PAGE_SIZE; + while (start < end) { hcp->desc.pnext = (u32) (dma + 1); hcp->desc.cntinfo = HPCDMA_EOX; hcp++; dma++; start += sizeof(struct hpc_chunk); - }; + } hcp--; hcp->desc.pnext = hd->dma; + + IP28_IP26_CODE( + /* Force flush to memory and purge cached references ! */ + dma_cache_wback_inv(WD93CAC(hd->cpu), PAGE_SIZE); + ) } static struct Scsi_Host * __init sgiwd93_setup_scsi( @@ -233,13 +300,20 @@ static struct Scsi_Host * __init sgiwd93 host->irq = irq; hdata = HDATA(host); - hdata->hd.cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &hdata->hd.dma, - GFP_KERNEL); + hdata->hd.cpu = dma_alloc_coherent(NULL, DMA_NONCOHERENT_CODE(2*)PAGE_SIZE, + &hdata->hd.dma, GFP_KERNEL); if (!hdata->hd.cpu) { printk(KERN_WARNING "sgiwd93: Could not allocate memory for " "host %d buffer.\n", unit); goto out_unregister; } + hdata->hd.rb.rbp = 0; + hdata->hd.rb.scp = 0; + hdata->hd.rb.len = 0; + hdata->hd.buf = 0; + DMA_NONCOHERENT_CODE( + hdata->hd.buf = (void*) ((char*)hdata->hd.cpu + PAGE_SIZE); + ) init_hpc_chain(&hdata->hd); regs.SASR = wdregs + 3; @@ -257,7 +331,8 @@ static struct Scsi_Host * __init sgiwd93 return host; out_free: - dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma); + dma_free_coherent(NULL, DMA_NONCOHERENT_CODE(2*)PAGE_SIZE, + hdata->hd.cpu, hdata->hd.dma); wd33c93_release(); out_unregister: @@ -300,7 +375,8 @@ int sgiwd93_release(struct Scsi_Host *in irq = SGI_WD93_1_IRQ; free_irq(irq, sgiwd93_intr); - dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma); + dma_free_coherent(NULL, DMA_NONCOHERENT_CODE(2*)PAGE_SIZE, + hdata->hd.cpu, hdata->hd.dma); wd33c93_release(); return 1; @@ -320,6 +396,96 @@ static int sgiwd93_bus_reset(Scsi_Cmnd * return SUCCESS; } +static dma_addr_t sgiwd93_dma_map( Scsi_Cmnd *cmd ) +{ + struct ip22_hostdata *hdata = HDATA(cmd->device->host); + unsigned len = cmd->SCp.this_residual; + void *addr = cmd->SCp.ptr; + /* + * We cannot use 'cmd->sc_data_direction' here, since we are called + * for an explicit dma-direction, and it is mere *concidence*, if + * 'sc_data_direction' is consistent with this direction ! + * (tracing shows, 'sc_...' isn't well defined at all...) + */ + int dmadir = hdata->wh.dma_dir ? DMA_FROM_DEVICE:DMA_TO_DEVICE; + + DMA_NONCOHERENT_CODE( + if (hdata->hd.rb.rbp) { + printk(KERN_ERR "sgiwd93_dma_map: %s: discarding stale input buffer!" + " (%p)\n", hdata->wh.dma_dir ? "in":"out", hdata->hd.rb.scp); + if (hdata->hd.rb.rbp != hdata->hd.buf) + kfree(hdata->hd.rb.rbp); + } + hdata->hd.rb.scp = addr; + hdata->hd.rb.rbp = 0; + hdata->hd.rb.len = len; + if (hdata->wh.dma_dir) { + /* + * (at least by now) it seems, we cannot safely avoid + * to intercept *all* input-buffers on IP28. + */ + if (IP28_IP26_CODE(1 || )CACHLIGNUP(len) != len || + CACHLIGNDN((unsigned)addr) != (unsigned)addr) { + len = CACHLIGNUP(len); + if (len <= sizeof(*hdata->hd.buf)) { + hdata->hd.rb.rbp = addr = hdata->hd.buf; + /* Sigh... Screw it, to make dma_map_single() work. */ + addr = phys_to_virt( WD93PHYS(addr) ); + } else { + if ( !(addr = kmalloc(len, GFP_KERNEL)) ) + return (cmd->SCp.dma_handle = 0); + hdata->hd.rb.rbp = addr; + } + } + }) + cmd->SCp.dma_handle = dma_map_single(NULL, addr, len, dmadir); + return cmd->SCp.dma_handle; +} + +static void sgiwd93_dma_unmap( Scsi_Cmnd *cmd ) +{ + struct ip22_hostdata *hdata = HDATA(cmd->device->host); + unsigned len = cmd->SCp.this_residual; + +#ifdef CONFIG_CPU_R10000 + /* R10000 on non-cachecoherent systems needs special care */ + DMA_NONCOHERENT_CODE( + if (hdata->hd.rb.rbp) + dma_cache_inv(WD93CAC(hdata->hd.rb.rbp), + CACHLIGNUP(hdata->hd.rb.len)); + else if (hdata->wh.dma_dir) + dma_cache_inv((unsigned long)cmd->SCp.ptr, len); + ) +#endif + DMA_NONCOHERENT_CODE( + /* We had dma_map'ed an aligned input buffer ! */ + if (hdata->wh.dma_dir) len = CACHLIGNUP(len); + ) + dma_unmap_single(NULL, cmd->SCp.dma_handle, len, + hdata->wh.dma_dir ? DMA_FROM_DEVICE:DMA_TO_DEVICE); + + DMA_NONCOHERENT_CODE( + if (cmd->SCp.ptr != hdata->hd.rb.scp) + printk(KERN_ERR "sgiwd93_dma_map: %s: mismatched SCp! (%p,%p)\n", + hdata->wh.dma_dir ? "in":"out", hdata->hd.rb.scp, + cmd->SCp.ptr); + if (hdata->hd.rb.rbp) { + if (!hdata->wh.dma_dir) + printk(KERN_ERR "sgiwd93_dma_unmap: out: discarding " + "stale input buffer! (%p)\n", hdata->hd.rb.scp); + else /* if (cmd->SCp.ptr == hdata->hd.rb.scp) */ + memcpy(hdata->hd.rb.scp, hdata->hd.rb.rbp, + hdata->hd.rb.len); + + if (hdata->hd.rb.rbp != hdata->hd.buf) + kfree(hdata->hd.rb.rbp); + } + hdata->hd.rb.scp = 0; + hdata->hd.rb.rbp = 0; + hdata->hd.rb.len = 0; + ) +} + /* * Kludge alert - the SCSI code calls the abort and reset method with int * arguments not with pointers. So this is going to blow up beautyfully @@ -342,3 +508,8 @@ static Scsi_Host_Template driver_templat .use_clustering = DISABLE_CLUSTERING, }; #include "scsi_module.c" +/* + * Revision 1.51, Sat Jun 26 15:15:18 2004 + * Revision 1.52, Tue Apr 12 14:00:38 2005 + * Jun/Dec 2004, Apr 2005 pf - xkphys, cache-alignment, IP28/IP26 + */ diff -Naurp linux-2.6.13.orig/drivers/scsi/wd33c93.c linux-2.6.13/drivers/scsi/wd33c93.c --- linux-2.6.13.orig/drivers/scsi/wd33c93.c 2005-08-28 19:41:01.000000000 -0400 +++ linux-2.6.13/drivers/scsi/wd33c93.c 2005-08-30 22:04:48.000000000 -0400 @@ -1460,7 +1460,7 @@ reset_wd33c93(struct Scsi_Host *instance 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 -Naurp linux-2.6.13.orig/drivers/serial/Kconfig linux-2.6.13/drivers/serial/Kconfig --- linux-2.6.13.orig/drivers/serial/Kconfig 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/drivers/serial/Kconfig 2005-08-30 22:04:48.000000000 -0400 @@ -555,16 +555,18 @@ config SERIAL_SUNSAB_CONSOLE 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 -Naurp linux-2.6.13.orig/drivers/video/Kconfig linux-2.6.13/drivers/video/Kconfig --- linux-2.6.13.orig/drivers/video/Kconfig 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/drivers/video/Kconfig 2005-08-30 22:04:48.000000000 -0400 @@ -568,6 +568,14 @@ config FB_GBE_MEM This is the amount of memory reserved for the framebuffer, which can be any value between 1MB and 8MB. +config FB_IMPACT + tristate "SGI Octane ImpactSR / Indigo2 Impact graphics support" + depends on FB && (SGI_IP22 || SGI_IP26 || SGI_IP28 || SGI_IP30) + select FB_SOFT_CURSOR + help + SGI Octane ImpactSR (SI/SSI/MXI/SE/SSE/MXE) graphics card support. + SGI Indigo2 Impact (SI/HI/MI) graphics card support. + config BUS_I2C bool depends on (FB = y) && VISWS diff -Naurp linux-2.6.13.orig/drivers/video/Makefile linux-2.6.13/drivers/video/Makefile --- linux-2.6.13.orig/drivers/video/Makefile 2005-08-30 21:46:38.000000000 -0400 +++ linux-2.6.13/drivers/video/Makefile 2005-08-30 22:06:02.000000000 -0400 @@ -93,6 +93,7 @@ obj-$(CONFIG_FB_TX3912) += tx3912fb.o obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_SMIVGX) += smivgxfb.o +obj-$(CONFIG_FB_IMPACT) += impact.o # Platform or fallback drivers go here obj-$(CONFIG_FB_VESA) += vesafb.o diff -Naurp linux-2.6.13.orig/drivers/video/impact.c linux-2.6.13/drivers/video/impact.c --- linux-2.6.13.orig/drivers/video/impact.c 1969-12-31 19:00:00.000000000 -0500 +++ linux-2.6.13/drivers/video/impact.c 2005-08-30 22:04:48.000000000 -0400 @@ -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