GIT 4a8f9c177afd8d0bd400826fa898abe002ed576f git+ssh://master.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6.git#master commit 4a8f9c177afd8d0bd400826fa898abe002ed576f Author: Kyle McMartin Date: Fri Aug 25 13:13:44 2006 -0400 [PARISC] Rename most of parisc-agp to distinguish it from hp-agp.c since it may diverge more in the future. Move a few common defines to ropes.h Signed-off-by: Kyle McMartin commit 0e9261cbb899e2240fd97f2e1728e6c06fd399e9 Author: Kyle McMartin Date: Fri Aug 25 12:28:24 2006 -0400 [PARISC] Move LBA and SBA register defines to the common ropes.h header. This will allow the use of more constants in the agpgart driver. Signed-off-by: Kyle McMartin commit a10b57839396eb9c99ade7ab0c2cb3cdb25f013e Author: Matthew Wilcox Date: Fri Aug 25 10:55:12 2006 -0600 [PATCH] VIA and SiS chipsets are only available on x86 machines Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin commit b445307ca29543dc0d3c8be948c5c4d09f684772 Author: Kyle McMartin Date: Thu Aug 24 21:33:40 2006 -0400 [PARISC] Add support for Quicksilver AGPGART Signed-off-by: Kyle McMartin commit 5c6f4a73db5e7e72888ee2732c841d175bed3a1f Author: Kyle McMartin Date: Thu Aug 24 21:32:49 2006 -0400 [PARISC] Create shared header Pull out struct sba_device and struct lba_device into a common ropes.h header. Also fold the parisc portion of iosapic.h into this file. (Then delete the useless portion of iosapic.h) Signed-off-by: Kyle McMartin commit b38cb8115317b2aaa5c05e63b94ad25140409648 Author: Kyle McMartin Date: Thu Aug 24 21:31:41 2006 -0400 [PARISC] Stash the lba_device in its struct device drvdata Signed-off-by: Kyle McMartin commit 781e65558edffefc866d11612fe030f5116d1125 Author: Kyle McMartin Date: Thu Aug 24 21:30:19 2006 -0400 [PARISC] Generalize IS_ASTRO et al to take a parisc_device like IS_ELROY. Also remove the useless caching of the parisc_device_id in struct sba_device. Signed-off-by: Kyle McMartin commit ae3917a8771ef9b808eabe031def7b2a5843cada Author: Kyle McMartin Date: Thu Aug 24 21:28:58 2006 -0400 [PARISC] Pretty print the name of the lba type on kernel boot (it's pretty useless telling a user they have a whole bunch of TR%d.%d LBAs) Signed-off-by: Kyle McMartin commit ed4e4fe1f248d4ed97a6b46d9eb67f506fca89f5 Author: Kyle McMartin Date: Sat Sep 16 15:25:48 2006 -0400 [PARISC] Convert parisc to generic irq handling Also make use of the specific ability to template interrupts for the timer and IPI interrupts. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin commit 72d07e829f72454131bd494404628725e984c2fe Author: James Bottomley Date: Fri Sep 15 07:33:33 2006 -0700 [PATCH] Add the ability to template irq handlers in the generic irq code On parisc, we have the issue that function call pointers are hugely expensive, so we'd like to minimise their use in the interrupts. Unfortunately, this involves directly calling the ack/eoi functions instead of indirecting. To permit this without losing the advantages of centrally managed irq code, I introduced template builders for irq handlers. This allows us to construct special handlers on parisc that don't indirect through function call pointers. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin commit a41f9147b251f0302ca34b6f13e10e6a1d5ea624 Author: Matthew Wilcox Date: Thu Sep 14 08:26:49 2006 -0600 [PARISC] headers_check: Clean up asm-parisc/page.h for user headers Remove definitions of PAGE_* from the user view Delete unnecessary comments referring to the size of pages Only include if we're in __KERNEL__ Signed-off-by: David Woodhouse Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin commit ba0c796ace18e3f0af1688e2f52124f8b2276349 Author: Matthew Wilcox Date: Tue Sep 12 05:19:15 2006 -0600 [PARISC] Remove some obsolete comments and I checked that Reo is similar to Ike Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin commit 3c1166d4ba48bfd13abe5f9da9fb473ef2ecab43 Author: Matthew Wilcox Date: Tue Sep 12 05:17:59 2006 -0600 [PARISC] Add hardware found in the rp8400 Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin commit bec4f9574cfae73d3d154607127a26ce336680b6 Author: James Bottomley Date: Sat Sep 9 12:36:25 2006 -0700 [PARISC] Allow nested interrupts Our prior mode of operation didn't allow nested interrupts because it makes the interrupt code much simpler. However, nested interrupts are better for latency. This code uses the EIEM register to simulate level interrupts and thus achieve nesting. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin commit 373ae60ca420836ab96b5ec995d6c9e60707bbcd Author: Grant Grundler Date: Sun Sep 10 12:57:55 2006 -0700 [PARISC] Further updates to timer_interrupt() This version (relative to the current tree): o eliminates "while (ticks_elapsed)" loop. It's not needed. o drop "ticks_elapsed" completely from timer_interrupt(). o Estimates elapsed cycles (based on HZ) to see which kind of math we want to use to calculate "cycles_remainder". o Fixes a bug where we would loose a tick if we decided we wanted to skip one interrupt. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin commit bd5decbc70fa3e822f2d2449e29b2b5e0dfc584b Author: Grant Grundler Date: Mon Sep 4 13:56:11 2006 -0700 [PARISC] remove halftick and copy clocktick to local var (gcc can optimize usage) Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin commit 7d2062e3bed7f1dbc209427457168fb6b189242c Author: Grant Grundler Date: Fri Sep 8 23:29:22 2006 -0700 [PARISC] Rewrite timer_interrupt() and gettimeoffset() using "unsigned" math. It's just a bit easier to follow and timer code is complex enough. So far, only tested on A500-5x (64-bit SMP), ie: gettimeoffset() code hasn't been tested at all. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin commit 5b61be8762eedcbb1e1b560299af8376642a3708 Author: Matthew Wilcox Date: Fri Sep 8 05:43:44 2006 -0600 [PARISC] Enable interrupts while spinning Use the __raw_spin_lock_flags routine so we can take an interrupt while spinning. This re-fixes a bug jejb found on 2005-10-20: CPU0 does a flush_tlb_all holding the vmlist_lock for write. CPU1 tries a cat of /proc/meminfo which tries to acquire vmlist_lock for read CPU1 is now spinning with interrupts disabled CPU0 tries to execute a smp_call_function to flush the local tlb caches This is now a deadlock because CPU1 is spinning with interrupts disabled and can never receive the IPI Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin commit b49530a03d369488db2bd55af2d4166f18e7bf04 Author: Grant Grundler Date: Sun Sep 3 00:02:16 2006 -0700 [PARISC] Add new function to start local Interval Timer, start_cpu_itimer() I couldn't find where the itimer was getting started for slave CPUs. CPU 0 (master) itimer was started in time_init() (arch/parisc/kernel/time.c). start_cpu_itimer() code was striped from time_init(). Slaves now start their itimer in smp_cpu_init(). This is a first step towards making gettimeoffset() work for SMP. Next step will be to determine the CR16 (cycle counter) offsets for each CPU relative to the master (CPU 0). Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin commit 757190cb4e14e93e3873c7bef6d5d6561eb2ee64 Author: Grant Grundler Date: Fri Sep 1 14:18:39 2006 -0700 [PARISC] Prevent processor_probe() from clobbering cpu_data[0] processor_probe() shouldn't clobber cpu_data[0] cpu_data[0].it_value (used by timer_interrupt()) is already set. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin commit 593ffcdb084bd445ee0b36888bb83678e76b5ab7 Author: Grant Grundler Date: Fri Sep 1 14:50:25 2006 -0700 [PARISC] Use CONFIG_HZ to determine interval timer rate (aka clock ticks) This isn't likely to be causing problems for other bits of kernel code. I can't find any other user of CONFIG_HZ outside of arch specific code. Signed-off-by: Grant Grundler Signed-off-by: Kyle McMartin commit 88b34dbeb12cc949e98063b4a62f40e0c0920caa Author: Carlos O'Donell Jr Date: Thu Sep 7 13:05:17 2006 -0400 [PARISC] Implement futex_atomic_cmpxchg_inatomic Implement trivial futex_atomic_cmpxchg_inatomic for testing. Signed-off-by: Carlos O'Donell Signed-off-by: Kyle McMartin commit c87016c9429e561b23a17823bfacaa8e9a1ee9ee Author: Matthew Wilcox Date: Sat Sep 2 07:54:58 2006 -0600 [PARISC] Improve rwlock implementation Rewrite rwlock implementation to avoid various deadlocks in the current scheme. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin commit 1f054aae03548c699448e2552fb99c731f2acaef Author: Kyle McMartin Date: Mon Aug 28 15:42:07 2006 -0400 [PARISC] [BUGFIX] nullify branch delay slot of the jump back to intr_restore in intr_do_preempt. This prevents the execution of an unwanted insn... Signed-off-by: Kyle McMartin commit a7349d401711307da30423e7b8c37623fbccb9e9 Author: Matthew Wilcox Date: Mon Aug 28 11:53:30 2006 -0600 [PARISC] Clean up asm-parisc/serial.h Russell King pointed out that asm/serial.h is anachronistic and we were misusing BASE_BAUD. So fix BASE_BAUD for PCI 16550 UARTs, move LASI_BASE_BAUD into 8250_gsc, and fix the obsolete comment about reserving serial port slots. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin commit f058959521dd5d61f5bf51f1f26a8127f8faf116 Author: Kyle McMartin Date: Sun Aug 27 11:12:13 2006 -0400 [PARISC] Allow overriding personality with sys_personality And now suddenly, linux32 works on parisc... Signed-off-by: Kyle McMartin commit 2384b9fed57aaaefe2aa55d7c9f107049be2edec Author: Kyle McMartin Date: Sun Aug 27 11:04:26 2006 -0400 [PARISC] Switch is_compat_task to use TIF_32BIT Stop using PER_LINUX32 to designate processes needing compaterizing. Convert is_compat_task to use TIF_32BIT and set TIF_32BIT in binfmt_elf32.c Signed-off-by: Kyle McMartin commit 10486a652cf2c9aa5db40c869bc63777e585656f Author: Kyle McMartin Date: Sat Sep 16 14:38:22 2006 -0400 [PARISC] Prevent multiple includes of asm-parisc/parisc-device.h Signed-off-by: Kyle McMartin commit cd9bfa6b9b79342891d52f9a50bc33b91cfc7fb0 Author: James Bottomley Date: Wed Aug 23 09:00:04 2006 -0700 [PARISC] parisc specific kmap API implementation for pa8800 This patch fixes the pa8800 at a gross level (there are still other subtle incoherency issues which can still cause crashes and HPMCs). What it does is try to force eject inequivalent aliases before they become visible to the L2 cache (which is where we get the incoherence problems). A new function (parisc_requires_coherency) is introduced in asm/processor.h to identify the pa8x00 processors (8800 and 8900) which have the issue. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin commit 215cf9fe9c94b470dad73a8ccf448d8b66998894 Author: Carlos O'Donell Date: Sat Sep 16 14:35:51 2006 -0400 [PARISC] Document that D-class can also use serial_mux Signed-off-by: Carlos O'Donell Signed-off-by: Kyle McMartin commit 24da2c5adc5b5fe879f0ba08eb7e4119c8ddff48 Author: James Bottomley Date: Sun Aug 13 22:34:55 2006 -0400 [PATCH] Add kmap API abstraction This patch allows the kmap/kunmap API to be abstracted for implementation purposes by architectures that don't implement highmem. The purpose of this is for those architectures that need to perform arch specific coherence operations on kmap/kunmap. Signed-off-by: James Bottomley Signed-off-by: Kyle McMartin commit 458b0a2aed962c62e517d60a33da9e7792377194 Author: Kyle McMartin Date: Sun Aug 13 22:25:45 2006 -0400 [PARISC] Fix up parisc irq handling for genirq changes Clean up enough to get things compiling again in the interim. Signed-off-by: Kyle McMartin commit b9c8f611a3e879c305e03fe877d49c7d8d67efdc Author: Kyle McMartin Date: Sun Aug 13 22:18:57 2006 -0400 [PARISC] Add asm-parisc/mckinley.h bus header Add header for McKinley bus related code. Remove extern decl of proc_mckinley_root in drivers/parisc/sba_iommu.c Signed-off-by: Kyle McMartin commit de2396baef9757af0e292980fbd14d58d51c5a01 Author: Kyle McMartin Date: Sun Aug 13 22:17:19 2006 -0400 [PARISC] Abstract shift register left in .S Abstract existing shift register left macros as shift register right are. This lends itself to a nice clean up of some #ifdef blocks in entry.S Signed-off-by: Kyle McMartin commit cefda3a75b881f5fdd0beeaf3773cd66d177d619 Author: Kyle McMartin Date: Sun Aug 13 21:09:31 2006 -0400 [PATCH] Need foward decl of task_struct in linux/debug_locks.h Signed-off-by: Kyle McMartin commit 5ab696e07ef978601743466d5bc2aa63cde3bec5 Author: Kyle McMartin Date: Sun Aug 13 20:39:48 2006 -0400 [PARISC] Remove variables decls duplicated from asm-generic/sections.h Signed-off-by: Kyle McMartin commit b60aeb0284cce2ad5b55bffd3ae6cce9d60ae30d Author: Kyle McMartin Date: Sun Aug 13 20:37:26 2006 -0400 [PARISC] PA7200 also supports prefetch for read It seems PA7200 processors also suppress traps on loads to %r0. This means we can prefetch for read on these cpus. Of course, we can't support prefetch for write, since that requires LOAD DOUBLEWORD which was added with PA2.0 Signed-off-by: Kyle McMartin commit ab6a339600cfddfdee223fa4c9fd6c9ee602a20c Author: Kyle McMartin Date: Sun Aug 13 22:15:47 2006 -0400 [PARISC] Untangle header include mess asm/processor.h on parisc wants spinlocks for cpuinfo, but linux/spinlock_types.h needs lockdep, and lockdep wants prefetch. This leads to a horrible circular dependancy, because is including something which depends on things which are not defined until the end of the file. Kludge around this by moving prefetch related code into and including it before , however this is just a temporary solution until this mess can be cleaned up. Signed-off-by: Kyle McMartin Signed-off-by: Andrew Morton --- arch/parisc/Kconfig | 2 arch/parisc/kernel/binfmt_elf32.c | 24 - arch/parisc/kernel/cache.c | 45 ++ arch/parisc/kernel/entry.S | 21 - arch/parisc/kernel/hardware.c | 3 arch/parisc/kernel/irq.c | 164 +++++----- arch/parisc/kernel/processor.c | 5 arch/parisc/kernel/signal.c | 5 arch/parisc/kernel/smp.c | 7 arch/parisc/kernel/sys_parisc.c | 45 ++ arch/parisc/kernel/syscall_table.S | 4 arch/parisc/kernel/time.c | 209 +++++++++---- arch/parisc/mm/init.c | 23 - drivers/char/agp/Kconfig | 14 drivers/char/agp/Makefile | 1 drivers/char/agp/parisc-agp.c | 416 +++++++++++++++++++++++++++ drivers/parisc/iosapic.c | 8 drivers/parisc/lba_pci.c | 122 ------- drivers/parisc/sba_iommu.c | 267 ++--------------- drivers/serial/8250_gsc.c | 4 drivers/serial/Kconfig | 9 include/asm-parisc/agp.h | 25 + include/asm-parisc/assembly.h | 6 include/asm-parisc/cacheflush.h | 30 + include/asm-parisc/compat.h | 4 include/asm-parisc/futex.h | 71 ++++ include/asm-parisc/iosapic.h | 53 --- include/asm-parisc/irq-handlers.h | 15 include/asm-parisc/irq.h | 28 + include/asm-parisc/mckinley.h | 9 include/asm-parisc/page.h | 22 - include/asm-parisc/param.h | 10 include/asm-parisc/parisc-device.h | 5 include/asm-parisc/prefetch.h | 39 ++ include/asm-parisc/processor.h | 39 -- include/asm-parisc/ropes.h | 322 ++++++++++++++++++++ include/asm-parisc/serial.h | 16 - include/asm-parisc/spinlock.h | 117 ++++--- include/linux/debug_locks.h | 2 kernel/irq/chip.c | 172 +++++++---- 40 files changed, 1600 insertions(+), 783 deletions(-) diff -puN arch/parisc/Kconfig~git-parisc arch/parisc/Kconfig --- a/arch/parisc/Kconfig~git-parisc +++ a/arch/parisc/Kconfig @@ -127,7 +127,7 @@ config PA11 config PREFETCH def_bool y - depends on PA8X00 + depends on PA8X00 || PA7200 config 64BIT bool "64-bit kernel" diff -puN arch/parisc/kernel/binfmt_elf32.c~git-parisc arch/parisc/kernel/binfmt_elf32.c --- a/arch/parisc/kernel/binfmt_elf32.c~git-parisc +++ a/arch/parisc/kernel/binfmt_elf32.c @@ -87,7 +87,7 @@ struct elf_prpsinfo32 */ #define SET_PERSONALITY(ex, ibcs2) \ - current->personality = PER_LINUX32; \ + set_thread_flag(TIF_32BIT); \ current->thread.map_base = DEFAULT_MAP_BASE32; \ current->thread.task_size = DEFAULT_TASK_SIZE32 \ @@ -102,25 +102,3 @@ cputime_to_compat_timeval(const cputime_ } #include "../../../fs/binfmt_elf.c" - -/* Set up a separate execution domain for ELF32 binaries running - * on an ELF64 kernel */ - -static struct exec_domain parisc32_exec_domain = { - .name = "Linux/ELF32", - .pers_low = PER_LINUX32, - .pers_high = PER_LINUX32, -}; - -static int __init parisc32_exec_init(void) -{ - /* steal the identity signal mappings from the default domain */ - parisc32_exec_domain.signal_map = default_exec_domain.signal_map; - parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap; - - register_exec_domain(&parisc32_exec_domain); - - return 0; -} - -__initcall(parisc32_exec_init); diff -puN arch/parisc/kernel/cache.c~git-parisc arch/parisc/kernel/cache.c --- a/arch/parisc/kernel/cache.c~git-parisc +++ a/arch/parisc/kernel/cache.c @@ -91,7 +91,8 @@ update_mmu_cache(struct vm_area_struct * flush_kernel_dcache_page(page); clear_bit(PG_dcache_dirty, &page->flags); - } + } else if (parisc_requires_coherency()) + flush_kernel_dcache_page(page); } void @@ -370,3 +371,45 @@ void parisc_setup_cache_timing(void) printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus()); } + +extern void purge_kernel_dcache_page(unsigned long); +extern void clear_user_page_asm(void *page, unsigned long vaddr); + +void +clear_user_page(void *page, unsigned long vaddr, struct page *pg) +{ + purge_kernel_dcache_page((unsigned long)page); + purge_tlb_start(); + pdtlb_kernel(page); + purge_tlb_end(); + clear_user_page_asm(page, vaddr); +} + +void flush_kernel_dcache_page_addr(void *addr) +{ + flush_kernel_dcache_page_asm(addr); + purge_tlb_start(); + pdtlb_kernel(addr); + purge_tlb_end(); +} +EXPORT_SYMBOL(flush_kernel_dcache_page_addr); + +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg) +{ + /* no coherency needed (all in kmap/kunmap) */ + copy_user_page_asm(vto, vfrom); + if (!parisc_requires_coherency()) + flush_kernel_dcache_page_asm(vto); +} +EXPORT_SYMBOL(copy_user_page); + +#ifdef CONFIG_PA8X00 + +void kunmap_parisc(void *addr) +{ + if (parisc_requires_coherency()) + flush_kernel_dcache_page_addr(addr); +} +EXPORT_SYMBOL(kunmap_parisc); +#endif diff -puN arch/parisc/kernel/entry.S~git-parisc arch/parisc/kernel/entry.S --- a/arch/parisc/kernel/entry.S~git-parisc +++ a/arch/parisc/kernel/entry.S @@ -30,6 +30,7 @@ #include +#include /* for L1_CACHE_SHIFT */ #include /* for LDREG/STREG defines */ #include #include @@ -478,11 +479,7 @@ bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */ copy \pmd,%r9 -#ifdef CONFIG_64BIT - shld %r9,PxD_VALUE_SHIFT,\pmd -#else - shlw %r9,PxD_VALUE_SHIFT,\pmd -#endif + SHLREG %r9,PxD_VALUE_SHIFT,\pmd EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */ shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd @@ -970,11 +967,7 @@ intr_return: /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount ** irq_stat[] is defined using ____cacheline_aligned. */ -#ifdef CONFIG_64BIT - shld %r1, 6, %r20 -#else - shlw %r1, 5, %r20 -#endif + SHLREG %r1,L1_CACHE_SHIFT,%r20 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ #endif /* CONFIG_SMP */ @@ -1076,7 +1069,7 @@ intr_do_preempt: BL preempt_schedule_irq, %r2 nop - b intr_restore /* ssm PSW_SM_I done by intr_restore */ + b,n intr_restore /* ssm PSW_SM_I done by intr_restore */ #endif /* CONFIG_PREEMPT */ .import do_signal,code @@ -2115,11 +2108,7 @@ syscall_check_bh: ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */ /* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */ -#ifdef CONFIG_64BIT - shld %r26, 6, %r20 -#else - shlw %r26, 5, %r20 -#endif + SHLREG %r26,L1_CACHE_SHIFT,%r20 add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */ #endif /* CONFIG_SMP */ diff -puN arch/parisc/kernel/hardware.c~git-parisc arch/parisc/kernel/hardware.c --- a/arch/parisc/kernel/hardware.c~git-parisc +++ a/arch/parisc/kernel/hardware.c @@ -231,6 +231,7 @@ static struct hp_hardware hp_hardware_li {HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"}, {HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"}, {HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"}, + {HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"}, {HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"}, {HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"}, {HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"}, @@ -584,8 +585,10 @@ static struct hp_hardware hp_hardware_li {HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"}, {HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"}, {HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"}, + {HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"}, {HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"}, {HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"}, + {HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"}, {HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"}, {HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"}, {HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"}, diff -puN arch/parisc/kernel/irq.c~git-parisc arch/parisc/kernel/irq.c --- a/arch/parisc/kernel/irq.c~git-parisc +++ a/arch/parisc/kernel/irq.c @@ -35,9 +35,6 @@ #undef PARISC_IRQ_CR16_COUNTS -extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *); -extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); - #define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq)) /* Bits in EIEM correlate with cpu_irq_action[]. @@ -45,6 +42,17 @@ extern irqreturn_t ipi_interrupt(int, vo */ static volatile unsigned long cpu_eiem = 0; +/* +** ack bitmap ... habitually set to 1, but reset to zero +** between ->ack() and ->end() of the interrupt to prevent +** re-interruption of a processing interrupt. +*/ +static volatile unsigned long global_ack_eiem = ~0UL; +/* +** Local bitmap, same as above but for per-cpu interrupts +*/ +static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL; + static void cpu_disable_irq(unsigned int irq) { unsigned long eirr_bit = EIEM_MASK(irq); @@ -62,13 +70,6 @@ static void cpu_enable_irq(unsigned int cpu_eiem |= eirr_bit; - /* FIXME: while our interrupts aren't nested, we cannot reset - * the eiem mask if we're already in an interrupt. Once we - * implement nested interrupts, this can go away - */ - if (!in_interrupt()) - set_eiem(cpu_eiem); - /* This is just a simple NOP IPI. But what it does is cause * all the other CPUs to do a set_eiem(cpu_eiem) at the end * of the interrupt handler */ @@ -84,13 +85,45 @@ static unsigned int cpu_startup_irq(unsi void no_ack_irq(unsigned int irq) { } void no_end_irq(unsigned int irq) { } +void cpu_ack_irq(struct irq_desc *dummy, unsigned int irq) +{ + unsigned long mask = EIEM_MASK(irq); + int cpu = smp_processor_id(); + + /* Clear in EIEM so we can no longer process */ + if (CHECK_IRQ_PER_CPU(irq_desc[irq].status)) + per_cpu(local_ack_eiem, cpu) &= ~mask; + else + global_ack_eiem &= ~mask; + + /* disable the interrupt */ + set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); + /* and now ack it */ + mtctl(mask, 23); +} + +void cpu_end_irq(struct irq_desc *dummy, unsigned int irq) +{ + unsigned long mask = EIEM_MASK(irq); + int cpu = smp_processor_id(); + + /* set it in the eiems---it's no longer in process */ + if (CHECK_IRQ_PER_CPU(irq_desc[irq].status)) + per_cpu(local_ack_eiem, cpu) |= mask; + else + global_ack_eiem |= mask; + + /* enable the interrupt */ + set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); +} + #ifdef CONFIG_SMP int cpu_check_affinity(unsigned int irq, cpumask_t *dest) { int cpu_dest; /* timer and ipi have to always be received on all CPUs */ - if (irq == TIMER_IRQ || irq == IPI_IRQ) { + if (CHECK_IRQ_PER_CPU(irq)) { /* Bad linux design decision. The mask has already * been set; we must reset it */ irq_desc[irq].affinity = CPU_MASK_ALL; @@ -119,8 +152,6 @@ static struct hw_interrupt_type cpu_inte .shutdown = cpu_disable_irq, .enable = cpu_enable_irq, .disable = cpu_disable_irq, - .ack = no_ack_irq, - .end = no_end_irq, #ifdef CONFIG_SMP .set_affinity = cpu_set_affinity_irq, #endif @@ -209,7 +240,7 @@ int show_interrupts(struct seq_file *p, ** Then use that to get the Transaction address and data. */ -int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data) +int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data) { if (irq_desc[irq].action) return -EBUSY; @@ -217,8 +248,8 @@ int cpu_claim_irq(unsigned int irq, stru return -EBUSY; if (type) { - irq_desc[irq].chip = type; - irq_desc[irq].chip_data = data; + set_irq_chip(irq, type); + set_irq_chip_data(irq, data); cpu_interrupt_type.enable(irq); } return 0; @@ -298,97 +329,86 @@ unsigned int txn_alloc_data(unsigned int return virt_irq - CPU_IRQ_BASE; } +static inline int eirr_to_irq(unsigned long eirr) +{ +#ifdef CONFIG_64BIT + int bit = fls64(eirr); +#else + int bit = fls(eirr); +#endif + return (BITS_PER_LONG - bit) + TIMER_IRQ; +} + /* ONLY called from entry.S:intr_extint() */ void do_cpu_irq_mask(struct pt_regs *regs) { unsigned long eirr_val; - - irq_enter(); - - /* - * Don't allow TIMER or IPI nested interrupts. - * Allowing any single interrupt to nest can lead to that CPU - * handling interrupts with all enabled interrupts unmasked. - */ - set_eiem(0UL); - - /* 1) only process IRQs that are enabled/unmasked (cpu_eiem) - * 2) We loop here on EIRR contents in order to avoid - * nested interrupts or having to take another interrupt - * when we could have just handled it right away. - */ - for (;;) { - unsigned long bit = (1UL << (BITS_PER_LONG - 1)); - unsigned int irq; - eirr_val = mfctl(23) & cpu_eiem; - if (!eirr_val) - break; - - mtctl(eirr_val, 23); /* reset bits we are going to process */ - - /* Work our way from MSb to LSb...same order we alloc EIRs */ - for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) { + int irq, cpu = smp_processor_id(); #ifdef CONFIG_SMP - cpumask_t dest = irq_desc[irq].affinity; + cpumask_t dest; #endif - if (!(bit & eirr_val)) - continue; - /* clear bit in mask - can exit loop sooner */ - eirr_val &= ~bit; + local_irq_disable(); + irq_enter(); -#ifdef CONFIG_SMP - /* FIXME: because generic set affinity mucks - * with the affinity before sending it to us - * we can get the situation where the affinity is - * wrong for our CPU type interrupts */ - if (irq != TIMER_IRQ && irq != IPI_IRQ && - !cpu_isset(smp_processor_id(), dest)) { - int cpu = first_cpu(dest); - - printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n", - irq, smp_processor_id(), cpu); - gsc_writel(irq + CPU_IRQ_BASE, - cpu_data[cpu].hpa); - continue; - } -#endif + eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem & + per_cpu(local_ack_eiem, cpu); + if (!eirr_val) + goto set_out; + irq = eirr_to_irq(eirr_val); - __do_IRQ(irq, regs); - } +#ifdef CONFIG_SMP + dest = irq_desc[irq].affinity; + if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) && + !cpu_isset(smp_processor_id(), dest)) { + int cpu = first_cpu(dest); + + printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n", + irq, smp_processor_id(), cpu); + gsc_writel(irq + CPU_IRQ_BASE, + cpu_data[cpu].hpa); + goto set_out; } +#endif + generic_handle_irq(irq, regs); - set_eiem(cpu_eiem); /* restore original mask */ + out: irq_exit(); -} + return; + set_out: + set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu)); + goto out; +} static struct irqaction timer_action = { .handler = timer_interrupt, .name = "timer", - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU, }; #ifdef CONFIG_SMP static struct irqaction ipi_action = { .handler = ipi_interrupt, .name = "IPI", - .flags = IRQF_DISABLED, + .flags = IRQF_DISABLED | IRQF_PERCPU, }; #endif static void claim_cpu_irqs(void) { int i; - for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) { - irq_desc[i].chip = &cpu_interrupt_type; - } + for (i = CPU_IRQ_BASE; i <= CPU_IRQ_MAX; i++) + set_irq_chip_and_handler(i, &cpu_interrupt_type, + handle_level_irq_chip); irq_desc[TIMER_IRQ].action = &timer_action; irq_desc[TIMER_IRQ].status |= IRQ_PER_CPU; + set_irq_handler(TIMER_IRQ, handle_specific_irq_timer); #ifdef CONFIG_SMP irq_desc[IPI_IRQ].action = &ipi_action; irq_desc[IPI_IRQ].status = IRQ_PER_CPU; + set_irq_handler(IPI_IRQ, handle_specific_irq_ipi); #endif } diff -puN arch/parisc/kernel/processor.c~git-parisc arch/parisc/kernel/processor.c --- a/arch/parisc/kernel/processor.c~git-parisc +++ a/arch/parisc/kernel/processor.c @@ -143,8 +143,9 @@ static int __init processor_probe(struct p = &cpu_data[cpuid]; boot_cpu_data.cpu_count++; - /* initialize counters */ - memset(p, 0, sizeof(struct cpuinfo_parisc)); + /* initialize counters - CPU 0 gets it_value set in time_init() */ + if (cpuid) + memset(p, 0, sizeof(struct cpuinfo_parisc)); p->loops_per_jiffy = loops_per_jiffy; p->dev = dev; /* Save IODC data in case we need it */ diff -puN arch/parisc/kernel/signal.c~git-parisc arch/parisc/kernel/signal.c --- a/arch/parisc/kernel/signal.c~git-parisc +++ a/arch/parisc/kernel/signal.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -433,13 +432,13 @@ setup_rt_frame(int sig, struct k_sigacti if (in_syscall) { regs->gr[31] = haddr; #ifdef __LP64__ - if (personality(current->personality) == PER_LINUX) + if (!test_thread_flag(TIF_32BIT)) sigframe_size |= 1; #endif } else { unsigned long psw = USER_PSW; #ifdef __LP64__ - if (personality(current->personality) == PER_LINUX) + if (!test_thread_flag(TIF_32BIT)) psw |= PSW_W; #endif diff -puN arch/parisc/kernel/smp.c~git-parisc arch/parisc/kernel/smp.c --- a/arch/parisc/kernel/smp.c~git-parisc +++ a/arch/parisc/kernel/smp.c @@ -262,6 +262,9 @@ ipi_interrupt(int irq, void *dev_id, str this_cpu, which); return IRQ_NONE; } /* Switch */ + /* let in any pending interrupts */ + local_irq_enable(); + local_irq_disable(); } /* while (ops) */ } return IRQ_HANDLED; @@ -430,8 +433,9 @@ smp_do_timer(struct pt_regs *regs) static void __init smp_cpu_init(int cpunum) { - extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */ + extern int init_per_cpu(int); /* arch/parisc/kernel/processor.c */ extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */ + extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */ /* Set modes and Enable floating point coprocessor */ (void) init_per_cpu(cpunum); @@ -457,6 +461,7 @@ smp_cpu_init(int cpunum) enter_lazy_tlb(&init_mm, current); init_IRQ(); /* make sure no IRQ's are enabled or pending */ + start_cpu_itimer(); } diff -puN arch/parisc/kernel/sys_parisc.c~git-parisc arch/parisc/kernel/sys_parisc.c --- a/arch/parisc/kernel/sys_parisc.c~git-parisc +++ a/arch/parisc/kernel/sys_parisc.c @@ -31,6 +31,8 @@ #include #include #include +#include +#include int sys_pipe(int __user *fildes) { @@ -248,3 +250,46 @@ asmlinkage int sys_free_hugepages(unsign { return -EINVAL; } + +long parisc_personality(unsigned long personality) +{ + long err; + + if (personality(current->personality) == PER_LINUX32 + && personality == PER_LINUX) + personality = PER_LINUX32; + + err = sys_personality(personality); + if (err == PER_LINUX32) + err = PER_LINUX; + + return err; +} + +static inline int override_machine(char __user *mach) { +#ifdef CONFIG_COMPAT + if (personality(current->personality) == PER_LINUX32) { + if (__put_user(0, mach + 6) || + __put_user(0, mach + 7)) + return -EFAULT; + } + + return 0; +#else /*!CONFIG_COMPAT*/ + return 0; +#endif /*CONFIG_COMPAT*/ +} + +long parisc_newuname(struct new_utsname __user *utsname) +{ + int err = 0; + + down_read(&uts_sem); + if (copy_to_user(utsname, &system_utsname, sizeof(*utsname))) + err = -EFAULT; + up_read(&uts_sem); + + err = override_machine(utsname->machine); + + return (long)err; +} diff -puN arch/parisc/kernel/syscall_table.S~git-parisc arch/parisc/kernel/syscall_table.S --- a/arch/parisc/kernel/syscall_table.S~git-parisc +++ a/arch/parisc/kernel/syscall_table.S @@ -132,7 +132,7 @@ ENTRY_SAME(socketpair) ENTRY_SAME(setpgid) ENTRY_SAME(send) - ENTRY_SAME(newuname) + ENTRY_OURS(newuname) ENTRY_SAME(umask) /* 60 */ ENTRY_SAME(chroot) ENTRY_SAME(ustat) @@ -221,7 +221,7 @@ ENTRY_SAME(fchdir) ENTRY_SAME(bdflush) ENTRY_SAME(sysfs) /* 135 */ - ENTRY_SAME(personality) + ENTRY_OURS(personality) ENTRY_SAME(ni_syscall) /* for afs_syscall */ ENTRY_SAME(setfsuid) ENTRY_SAME(setfsgid) diff -puN arch/parisc/kernel/time.c~git-parisc arch/parisc/kernel/time.c --- a/arch/parisc/kernel/time.c~git-parisc +++ a/arch/parisc/kernel/time.c @@ -35,8 +35,7 @@ /* xtime and wall_jiffies keep wall-clock time */ extern unsigned long wall_jiffies; -static long clocktick __read_mostly; /* timer cycles per tick */ -static long halftick __read_mostly; +static unsigned long clocktick __read_mostly; /* timer cycles per tick */ #ifdef CONFIG_SMP extern void smp_do_timer(struct pt_regs *regs); @@ -44,46 +43,106 @@ extern void smp_do_timer(struct pt_regs irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - long now; - long next_tick; - int nticks; - int cpu = smp_processor_id(); + unsigned long now; + unsigned long next_tick; + unsigned long cycles_elapsed; + unsigned long cycles_remainder; + unsigned int cpu = smp_processor_id(); + + /* gcc can optimize for "read-only" case with a local clocktick */ + unsigned long cpt = clocktick; profile_tick(CPU_PROFILING, regs); - now = mfctl(16); - /* initialize next_tick to time at last clocktick */ + /* Initialize next_tick to the expected tick time. */ next_tick = cpu_data[cpu].it_value; - /* since time passes between the interrupt and the mfctl() - * above, it is never true that last_tick + clocktick == now. If we - * never miss a clocktick, we could set next_tick = last_tick + clocktick - * but maybe we'll miss ticks, hence the loop. - * - * Variables are *signed*. + /* Get current interval timer. + * CR16 reads as 64 bits in CPU wide mode. + * CR16 reads as 32 bits in CPU narrow mode. */ + now = mfctl(16); + + cycles_elapsed = now - next_tick; - nticks = 0; - while((next_tick - now) < halftick) { - next_tick += clocktick; - nticks++; + if ((cycles_elapsed >> 5) < cpt) { + /* use "cheap" math (add/subtract) instead + * of the more expensive div/mul method + */ + cycles_remainder = cycles_elapsed; + while (cycles_remainder > cpt) { + cycles_remainder -= cpt; + } + } else { + cycles_remainder = cycles_elapsed % cpt; } - mtctl(next_tick, 16); + + /* Can we differentiate between "early CR16" (aka Scenario 1) and + * "long delay" (aka Scenario 3)? I don't think so. + * + * We expected timer_interrupt to be delivered at least a few hundred + * cycles after the IT fires. But it's arbitrary how much time passes + * before we call it "late". I've picked one second. + */ +/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ +#if HZ == 1000 + if (cycles_elapsed > (cpt << 10) ) +#elif HZ == 250 + if (cycles_elapsed > (cpt << 8) ) +#elif HZ == 100 + if (cycles_elapsed > (cpt << 7) ) +#else +#warn WTF is HZ set to anyway? + if (cycles_elapsed > (HZ * cpt) ) +#endif + { + /* Scenario 3: very long delay? bad in any case */ + printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" + " cycles %lX rem %lX " + " next/now %lX/%lX\n", + cpu, + cycles_elapsed, cycles_remainder, + next_tick, now ); + } + + /* convert from "division remainder" to "remainder of clock tick" */ + cycles_remainder = cpt - cycles_remainder; + + /* Determine when (in CR16 cycles) next IT interrupt will fire. + * We want IT to fire modulo clocktick even if we miss/skip some. + * But those interrupts don't in fact get delivered that regularly. + */ + next_tick = now + cycles_remainder; + cpu_data[cpu].it_value = next_tick; - while (nticks--) { + /* Skip one clocktick on purpose if we are likely to miss next_tick. + * We want to avoid the new next_tick being less than CR16. + * If that happened, itimer wouldn't fire until CR16 wrapped. + * We'll catch the tick we missed on the tick after that. + */ + if (!(cycles_remainder >> 13)) + next_tick += cpt; + + /* Program the IT when to deliver the next interrupt. */ + /* Only bottom 32-bits of next_tick are written to cr16. */ + mtctl(next_tick, 16); + + + /* Done mucking with unreliable delivery of interrupts. + * Go do system house keeping. + */ #ifdef CONFIG_SMP - smp_do_timer(regs); + smp_do_timer(regs); #else - update_process_times(user_mode(regs)); + update_process_times(user_mode(regs)); #endif - if (cpu == 0) { - write_seqlock(&xtime_lock); - do_timer(regs); - write_sequnlock(&xtime_lock); - } + if (cpu == 0) { + write_seqlock(&xtime_lock); + do_timer(regs); + write_sequnlock(&xtime_lock); } - + /* check soft power switch status */ if (cpu == 0 && !atomic_read(&power_tasklet.count)) tasklet_schedule(&power_tasklet); @@ -109,14 +168,12 @@ unsigned long profile_pc(struct pt_regs EXPORT_SYMBOL(profile_pc); -/*** converted from ia64 ***/ /* * Return the number of micro-seconds that elapsed since the last * update to wall time (aka xtime aka wall_jiffies). The xtime_lock * must be at least read-locked when calling this routine. */ -static inline unsigned long -gettimeoffset (void) +static inline unsigned long gettimeoffset (void) { #ifndef CONFIG_SMP /* @@ -124,21 +181,47 @@ gettimeoffset (void) * Once parisc-linux learns the cr16 difference between processors, * this could be made to work. */ - long last_tick; - long elapsed_cycles; - - /* it_value is the intended time of the next tick */ - last_tick = cpu_data[smp_processor_id()].it_value; + unsigned long now; + unsigned long prev_tick; + unsigned long next_tick; + unsigned long elapsed_cycles; + unsigned long usec; + unsigned long cpuid = smp_processor_id(); + unsigned long cpt = clocktick; + + next_tick = cpu_data[cpuid].it_value; + now = mfctl(16); /* Read the hardware interval timer. */ + + prev_tick = next_tick - cpt; + + /* Assume Scenario 1: "now" is later than prev_tick. */ + elapsed_cycles = now - prev_tick; + +/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */ +#if HZ == 1000 + if (elapsed_cycles > (cpt << 10) ) +#elif HZ == 250 + if (elapsed_cycles > (cpt << 8) ) +#elif HZ == 100 + if (elapsed_cycles > (cpt << 7) ) +#else +#warn WTF is HZ set to anyway? + if (elapsed_cycles > (HZ * cpt) ) +#endif + { + /* Scenario 3: clock ticks are missing. */ + printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!" + " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n", + cpuid, elapsed_cycles / cpt, + elapsed_cycles, prev_tick, now, next_tick, cpt); + } - /* Subtract one tick and account for possible difference between - * when we expected the tick and when it actually arrived. - * (aka wall vs real) - */ - last_tick -= clocktick * (jiffies - wall_jiffies + 1); - elapsed_cycles = mfctl(16) - last_tick; + /* FIXME: Can we improve the precision? Not with PAGE0. */ + usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec; - /* the precision of this math could be improved */ - return elapsed_cycles / (PAGE0->mem_10msec / 10000); + /* add in "lost" jiffies */ + usec += cpt * (jiffies - wall_jiffies); + return usec; #else return 0; #endif @@ -149,6 +232,7 @@ do_gettimeofday (struct timeval *tv) { unsigned long flags, seq, usec, sec; + /* Hold xtime_lock and adjust timeval. */ do { seq = read_seqbegin_irqsave(&xtime_lock, flags); usec = gettimeoffset(); @@ -156,25 +240,13 @@ do_gettimeofday (struct timeval *tv) usec += (xtime.tv_nsec / 1000); } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); - if (unlikely(usec > LONG_MAX)) { - /* This can happen if the gettimeoffset adjustment is - * negative and xtime.tv_nsec is smaller than the - * adjustment */ - printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec); - usec += USEC_PER_SEC; - --sec; - /* This should never happen, it means the negative - * time adjustment was more than a second, so there's - * something seriously wrong */ - BUG_ON(usec > LONG_MAX); - } - - + /* Move adjusted usec's into sec's. */ while (usec >= USEC_PER_SEC) { usec -= USEC_PER_SEC; ++sec; } + /* Return adjusted result. */ tv->tv_sec = sec; tv->tv_usec = usec; } @@ -226,22 +298,23 @@ unsigned long long sched_clock(void) } +void __init start_cpu_itimer(void) +{ + unsigned int cpu = smp_processor_id(); + unsigned long next_tick = mfctl(16) + clocktick; + + mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */ + + cpu_data[cpu].it_value = next_tick; +} + void __init time_init(void) { - unsigned long next_tick; static struct pdc_tod tod_data; clocktick = (100 * PAGE0->mem_10msec) / HZ; - halftick = clocktick / 2; - /* Setup clock interrupt timing */ - - next_tick = mfctl(16); - next_tick += clocktick; - cpu_data[smp_processor_id()].it_value = next_tick; - - /* kick off Itimer (CR16) */ - mtctl(next_tick, 16); + start_cpu_itimer(); /* get CPU 0 started */ if(pdc_tod_read(&tod_data) == 0) { write_seqlock_irq(&xtime_lock); diff -puN arch/parisc/mm/init.c~git-parisc arch/parisc/mm/init.c --- a/arch/parisc/mm/init.c~git-parisc +++ a/arch/parisc/mm/init.c @@ -31,10 +31,7 @@ DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); -extern char _text; /* start of kernel code, defined by linker */ extern int data_start; -extern char _end; /* end of BSS, defined by linker */ -extern char __init_begin, __init_end; #ifdef CONFIG_DISCONTIGMEM struct node_map_data node_data[MAX_NUMNODES] __read_mostly; @@ -319,8 +316,8 @@ static void __init setup_bootmem(void) reserve_bootmem_node(NODE_DATA(0), 0UL, (unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE)); - reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text), - (unsigned long)(&_end - &_text)); + reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text), + (unsigned long)(_end - _text)); reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT), ((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT)); @@ -355,8 +352,8 @@ static void __init setup_bootmem(void) #endif data_resource.start = virt_to_phys(&data_start); - data_resource.end = virt_to_phys(&_end)-1; - code_resource.start = virt_to_phys(&_text); + data_resource.end = virt_to_phys(_end) - 1; + code_resource.start = virt_to_phys(_text); code_resource.end = virt_to_phys(&data_start)-1; /* We don't know which region the kernel will be in, so try @@ -385,12 +382,12 @@ void free_initmem(void) */ local_irq_disable(); - memset(&__init_begin, 0x00, - (unsigned long)&__init_end - (unsigned long)&__init_begin); + memset(__init_begin, 0x00, + (unsigned long)__init_end - (unsigned long)__init_begin); flush_data_cache(); asm volatile("sync" : : ); - flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end); + flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end); asm volatile("sync" : : ); local_irq_enable(); @@ -398,8 +395,8 @@ void free_initmem(void) /* align __init_begin and __init_end to page size, ignoring linker script where we might have tried to save RAM */ - init_begin = PAGE_ALIGN((unsigned long)(&__init_begin)); - init_end = PAGE_ALIGN((unsigned long)(&__init_end)); + init_begin = PAGE_ALIGN((unsigned long)(__init_begin)); + init_end = PAGE_ALIGN((unsigned long)(__init_end)); for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); init_page_count(virt_to_page(addr)); @@ -578,7 +575,7 @@ static void __init map_pages(unsigned lo extern const unsigned long fault_vector_20; extern void * const linux_gateway_page; - ro_start = __pa((unsigned long)&_text); + ro_start = __pa((unsigned long)_text); ro_end = __pa((unsigned long)&data_start); fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK; gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK; diff -puN drivers/char/agp/Kconfig~git-parisc drivers/char/agp/Kconfig --- a/drivers/char/agp/Kconfig~git-parisc +++ a/drivers/char/agp/Kconfig @@ -1,6 +1,6 @@ config AGP tristate "/dev/agpgart (AGP Support)" - depends on ALPHA || IA64 || PPC || X86 + depends on ALPHA || IA64 || PARISC || PPC || X86 depends on PCI ---help--- AGP (Accelerated Graphics Port) is a bus system mainly used to @@ -86,7 +86,7 @@ config AGP_NVIDIA config AGP_SIS tristate "SiS chipset support" - depends on AGP + depends on AGP && X86 help This option gives you AGP support for the GLX component of X on Silicon Integrated Systems [SiS] chipsets. @@ -103,7 +103,7 @@ config AGP_SWORKS config AGP_VIA tristate "VIA chipset support" - depends on AGP + depends on AGP && X86 help This option gives you AGP support for the GLX component of X on VIA MVP3/Apollo Pro chipsets. @@ -122,6 +122,14 @@ config AGP_HP_ZX1 This option gives you AGP GART support for the HP ZX1 chipset for IA64 processors. +config AGP_PARISC + tristate "HP Quicksilver AGP support" + depends on AGP && PARISC && 64BIT + help + This option gives you AGP GART support for the HP Quicksilver + AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000 + workstation...) + config AGP_ALPHA_CORE tristate "Alpha AGP support" depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL) diff -puN drivers/char/agp/Makefile~git-parisc drivers/char/agp/Makefile --- a/drivers/char/agp/Makefile~git-parisc +++ a/drivers/char/agp/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_AGP_AMD64) += amd64-agp.o obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o obj-$(CONFIG_AGP_EFFICEON) += efficeon-agp.o obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o +obj-$(CONFIG_AGP_PARISC) += parisc-agp.o obj-$(CONFIG_AGP_I460) += i460-agp.o obj-$(CONFIG_AGP_INTEL) += intel-agp.o obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o diff -puN /dev/null drivers/char/agp/parisc-agp.c --- /dev/null +++ a/drivers/char/agp/parisc-agp.c @@ -0,0 +1,416 @@ +/* + * HP Quicksilver AGP GART routines + * + * Copyright (c) 2006, Kyle McMartin + * + * Based on drivers/char/agpgart/hp-agp.c which is + * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P. + * Bjorn Helgaas + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include "agp.h" + +#define DRVNAME "quicksilver" +#define DRVPFX DRVNAME ": " + +#ifndef log2 +#define log2(x) ffz(~(x)) +#endif + +#define AGP8X_MODE_BIT 3 +#define AGP8X_MODE (1 << AGP8X_MODE_BIT) + +static struct _parisc_agp_info { + void __iomem *ioc_regs; + void __iomem *lba_regs; + + int lba_cap_offset; + + u64 *gatt; + u64 gatt_entries; + + u64 gart_base; + u64 gart_size; + + int io_page_size; + int io_pages_per_kpage; +} parisc_agp_info; + +static struct gatt_mask parisc_agp_masks[] = +{ + { + .mask = SBA_PDIR_VALID_BIT, + .type = 0 + } +}; + +static struct aper_size_info_fixed parisc_agp_sizes[] = +{ + {0, 0, 0}, /* filled in by parisc_agp_fetch_size() */ +}; + +static int +parisc_agp_fetch_size(void) +{ + int size; + + size = parisc_agp_info.gart_size / MB(1); + parisc_agp_sizes[0].size = size; + agp_bridge->current_size = (void *) &parisc_agp_sizes[0]; + + return size; +} + +static int +parisc_agp_configure(void) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + + agp_bridge->gart_bus_addr = info->gart_base; + agp_bridge->capndx = info->lba_cap_offset; + agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS); + + return 0; +} + +static void +parisc_agp_tlbflush(struct agp_memory *mem) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + + writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM); + readq(info->ioc_regs+IOC_PCOM); /* flush */ +} + +static int +parisc_agp_create_gatt_table(struct agp_bridge_data *bridge) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int i; + + for (i = 0; i < info->gatt_entries; i++) { + info->gatt[i] = (unsigned long)agp_bridge->scratch_page; + } + + return 0; +} + +static int +parisc_agp_free_gatt_table(struct agp_bridge_data *bridge) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + + info->gatt[0] = SBA_AGPGART_COOKIE; + + return 0; +} + +static int +parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int i, k; + off_t j, io_pg_start; + int io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = info->io_pages_per_kpage * pg_start; + io_pg_count = info->io_pages_per_kpage * mem->page_count; + if ((io_pg_start + io_pg_count) > info->gatt_entries) { + return -EINVAL; + } + + j = io_pg_start; + while (j < (io_pg_start + io_pg_count)) { + if (info->gatt[j]) + return -EBUSY; + j++; + } + + if (mem->is_flushed == FALSE) { + global_cache_flush(); + mem->is_flushed = TRUE; + } + + for (i = 0, j = io_pg_start; i < mem->page_count; i++) { + unsigned long paddr; + + paddr = mem->memory[i]; + for (k = 0; + k < info->io_pages_per_kpage; + k++, j++, paddr += info->io_page_size) { + info->gatt[j] = + agp_bridge->driver->mask_memory(agp_bridge, + paddr, type); + } + } + + agp_bridge->driver->tlb_flush(mem); + + return 0; +} + +static int +parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int i, io_pg_start, io_pg_count; + + if (type != 0 || mem->type != 0) { + return -EINVAL; + } + + io_pg_start = info->io_pages_per_kpage * pg_start; + io_pg_count = info->io_pages_per_kpage * mem->page_count; + for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) { + info->gatt[i] = agp_bridge->scratch_page; + } + + agp_bridge->driver->tlb_flush(mem); + return 0; +} + +static unsigned long +parisc_agp_mask_memory(struct agp_bridge_data *bridge, + unsigned long addr, int type) +{ + return SBA_PDIR_VALID_BIT | addr; +} + +static void +parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + u32 command; + + command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS); + + command = agp_collect_device_status(bridge, mode, command); + command |= 0x00000100; + + writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND); + + agp_device_command(command, (mode & AGP8X_MODE) != 0); +} + +struct agp_bridge_driver parisc_agp_driver = { + .owner = THIS_MODULE, + .size_type = FIXED_APER_SIZE, + .configure = parisc_agp_configure, + .fetch_size = parisc_agp_fetch_size, + .tlb_flush = parisc_agp_tlbflush, + .mask_memory = parisc_agp_mask_memory, + .masks = parisc_agp_masks, + .agp_enable = parisc_agp_enable, + .cache_flush = global_cache_flush, + .create_gatt_table = parisc_agp_create_gatt_table, + .free_gatt_table = parisc_agp_free_gatt_table, + .insert_memory = parisc_agp_insert_memory, + .remove_memory = parisc_agp_remove_memory, + .alloc_by_type = agp_generic_alloc_by_type, + .free_by_type = agp_generic_free_by_type, + .agp_alloc_page = agp_generic_alloc_page, + .agp_destroy_page = agp_generic_destroy_page, + .cant_use_aperture = 1, +}; + +static int __init +agp_ioc_init(void __iomem *ioc_regs) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + u64 *iova_base, *io_pdir, io_tlb_ps; + int io_tlb_shift; + + printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n"); + + info->ioc_regs = ioc_regs; + + io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG); + switch (io_tlb_ps) { + case 0: io_tlb_shift = 12; break; + case 1: io_tlb_shift = 13; break; + case 2: io_tlb_shift = 14; break; + case 3: io_tlb_shift = 16; break; + default: + printk(KERN_ERR DRVPFX "Invalid IOTLB page size " + "configuration 0x%llx\n", io_tlb_ps); + info->gatt = NULL; + info->gatt_entries = 0; + return -ENODEV; + } + info->io_page_size = 1 << io_tlb_shift; + info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size; + + iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1; + info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE; + + info->gart_size = PLUTO_GART_SIZE; + info->gatt_entries = info->gart_size / info->io_page_size; + + io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE)); + info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT]; + + if (info->gatt[0] != SBA_AGPGART_COOKIE) { + info->gatt = NULL; + info->gatt_entries = 0; + printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; " + "GART disabled\n"); + return -ENODEV; + } + + return 0; +} + +static int +lba_find_capability(int cap) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + u16 status; + u8 pos, id; + int ttl = 48; + + status = readw(info->lba_regs + PCI_STATUS); + if (!(status & PCI_STATUS_CAP_LIST)) + return 0; + pos = readb(info->lba_regs + PCI_CAPABILITY_LIST); + while (ttl-- && pos >= 0x40) { + pos &= ~3; + id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID); + if (id == 0xff) + break; + if (id == cap) + return pos; + pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT); + } + return 0; +} + +static int __init +agp_lba_init(void __iomem *lba_hpa) +{ + struct _parisc_agp_info *info = &parisc_agp_info; + int cap; + + info->lba_regs = lba_hpa; + info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP); + + cap = readl(lba_hpa + info->lba_cap_offset) & 0xff; + if (cap != PCI_CAP_ID_AGP) { + printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n", + cap, info->lba_cap_offset); + return -ENODEV; + } + + return 0; +} + +static int __init +parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa) +{ + struct pci_dev *fake_bridge_dev = NULL; + struct agp_bridge_data *bridge; + int error = 0; + + fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL); + if (!fake_bridge_dev) { + error = -ENOMEM; + goto fail; + } + + error = agp_ioc_init(ioc_hpa); + if (error) + goto fail; + + error = agp_lba_init(lba_hpa); + if (error) + goto fail; + + bridge = agp_alloc_bridge(); + if (!bridge) { + error = -ENOMEM; + goto fail; + } + bridge->driver = &parisc_agp_driver; + + fake_bridge_dev->vendor = PCI_VENDOR_ID_HP; + fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA; + bridge->dev = fake_bridge_dev; + + error = agp_add_bridge(bridge); + +fail: + return error; +} + +static struct device *next_device(struct klist_iter *i) { + struct klist_node * n = klist_next(i); + return n ? container_of(n, struct device, knode_parent) : NULL; +} + +static int +parisc_agp_init(void) +{ + extern struct sba_device *sba_list; + + int err = -1; + struct parisc_device *sba = NULL, *lba = NULL; + struct lba_device *lbadev = NULL; + struct device *dev = NULL; + struct klist_iter i; + + if (!sba_list) + goto out; + + /* Find our parent Pluto */ + sba = sba_list->dev; + if (!IS_PLUTO(sba)) { + printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n"); + goto out; + } + + /* Now search our Pluto for our precious AGP device... */ + klist_iter_init(&sba->dev.klist_children, &i); + while ((dev = next_device(&i))) { + struct parisc_device *padev = to_parisc_device(dev); + if (IS_QUICKSILVER(padev)) + lba = padev; + } + klist_iter_exit(&i); + + if (!lba) { + printk(KERN_INFO DRVPFX "No AGP devices found.\n"); + goto out; + } + + lbadev = parisc_get_drvdata(lba); + + /* w00t, let's go find our cookies... */ + parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr); + + return 0; + +out: + return err; +} + +module_init(parisc_agp_init); + +MODULE_AUTHOR("Kyle McMartin "); +MODULE_LICENSE("GPL"); diff -puN drivers/parisc/iosapic.c~git-parisc drivers/parisc/iosapic.c --- a/drivers/parisc/iosapic.c~git-parisc +++ a/drivers/parisc/iosapic.c @@ -146,7 +146,7 @@ #include #endif -#include +#include #include "./iosapic_private.h" #define MODULE_NAME "iosapic" @@ -686,12 +686,13 @@ printk("\n"); * i386/ia64 support ISA devices and have to deal with * edge-triggered interrupts too. */ -static void iosapic_end_irq(unsigned int irq) +void iosapic_end_irq(struct irq_desc *dummy, unsigned int irq) { struct vector_info *vi = iosapic_get_vector(irq); DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq, vi->eoi_addr, vi->eoi_data); iosapic_eoi(vi->eoi_addr, vi->eoi_data); + cpu_end_irq(NULL, irq); } static unsigned int iosapic_startup_irq(unsigned int irq) @@ -728,8 +729,6 @@ static struct hw_interrupt_type iosapic_ .shutdown = iosapic_disable_irq, .enable = iosapic_enable_irq, .disable = iosapic_disable_irq, - .ack = no_ack_irq, - .end = iosapic_end_irq, #ifdef CONFIG_SMP .set_affinity = iosapic_set_affinity_irq, #endif @@ -818,6 +817,7 @@ int iosapic_fixup_irq(void *isi_obj, str vi->eoi_data = cpu_to_le32(vi->txn_data); cpu_claim_irq(vi->txn_irq, &iosapic_interrupt_type, vi); + set_irq_handler(vi->txn_irq, handle_level_irq_iosapic); out: pcidev->irq = vi->txn_irq; diff -puN drivers/parisc/lba_pci.c~git-parisc drivers/parisc/lba_pci.c --- a/drivers/parisc/lba_pci.c~git-parisc +++ a/drivers/parisc/lba_pci.c @@ -46,9 +46,9 @@ #include #include +#include #include /* for register_parisc_driver() stuff */ #include -#include /* for iosapic_register() */ #include /* read/write stuff */ #undef DEBUG_LBA /* general stuff */ @@ -100,113 +100,10 @@ #define MODULE_NAME "LBA" -#define LBA_FUNC_ID 0x0000 /* function id */ -#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */ -#define LBA_CAPABLE 0x0030 /* capabilities register */ - -#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */ -#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */ - -#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */ -#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */ -#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */ - -#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */ -#define LBA_ARB_PRI 0x0088 /* firmware sets this. */ -#define LBA_ARB_MODE 0x0090 /* firmware sets this. */ -#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */ - -#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */ - -#define LBA_STAT_CTL 0x0108 /* Status & Control */ -#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */ -#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */ -#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */ -#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ - -#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */ -#define LBA_LMMIO_MASK 0x0208 - -#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */ -#define LBA_GMMIO_MASK 0x0218 - -#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */ -#define LBA_WLMMIO_MASK 0x0228 - -#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */ -#define LBA_WGMMIO_MASK 0x0238 - -#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */ -#define LBA_IOS_MASK 0x0248 - -#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */ -#define LBA_ELMMIO_MASK 0x0258 - -#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */ -#define LBA_EIOS_MASK 0x0268 - -#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */ -#define LBA_DMA_CTL 0x0278 /* firmware sets this */ - -#define LBA_IBASE 0x0300 /* SBA DMA support */ -#define LBA_IMASK 0x0308 - -/* FIXME: ignore DMA Hint stuff until we can measure performance */ -#define LBA_HINT_CFG 0x0310 -#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */ - -#define LBA_BUS_MODE 0x0620 - -/* ERROR regs are needed for config cycle kluges */ -#define LBA_ERROR_CONFIG 0x0680 -#define LBA_SMART_MODE 0x20 -#define LBA_ERROR_STATUS 0x0688 -#define LBA_ROPE_CTL 0x06A0 - -#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */ - /* non-postable I/O port space, densely packed */ #define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL) static void __iomem *astro_iop_base __read_mostly; -#define ELROY_HVERS 0x782 -#define MERCURY_HVERS 0x783 -#define QUICKSILVER_HVERS 0x784 - -static inline int IS_ELROY(struct parisc_device *d) -{ - return (d->id.hversion == ELROY_HVERS); -} - -static inline int IS_MERCURY(struct parisc_device *d) -{ - return (d->id.hversion == MERCURY_HVERS); -} - -static inline int IS_QUICKSILVER(struct parisc_device *d) -{ - return (d->id.hversion == QUICKSILVER_HVERS); -} - - -/* -** lba_device: Per instance Elroy data structure -*/ -struct lba_device { - struct pci_hba_data hba; - - spinlock_t lba_lock; - void *iosapic_obj; - -#ifdef CONFIG_64BIT - void __iomem * iop_base; /* PA_VIEW - for IO port accessor funcs */ -#endif - - int flags; /* state/functionality enabled */ - int hw_rev; /* HW revision of chip */ -}; - - static u32 lba_t32; /* lba flags */ @@ -1542,8 +1439,8 @@ lba_driver_probe(struct parisc_device *d default: version = "TR4+"; } - printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xf, dev->hpa.start); + printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n", + version, func_class & 0xf, dev->hpa.start); if (func_class < 2) { printk(KERN_WARNING "Can't support LBA older than " @@ -1563,14 +1460,18 @@ lba_driver_probe(struct parisc_device *d } } else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) { + int major, minor; + func_class &= 0xff; - version = kmalloc(6, GFP_KERNEL); - snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf)); + major = func_class >> 4, minor = func_class & 0xf; + /* We could use one printk for both Elroy and Mercury, * but for the mask for func_class. */ - printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n", - MODULE_NAME, version, func_class & 0xff, dev->hpa.start); + printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n", + IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major, + minor, func_class, dev->hpa.start); + cfg_ops = &mercury_cfg_ops; } else { printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start); @@ -1600,6 +1501,7 @@ lba_driver_probe(struct parisc_device *d lba_dev->hba.dev = dev; lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */ lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */ + parisc_set_drvdata(dev, lba_dev); /* ------------ Second : initialize common stuff ---------- */ pci_bios = &lba_bios_ops; diff -puN drivers/parisc/sba_iommu.c~git-parisc drivers/parisc/sba_iommu.c --- a/drivers/parisc/sba_iommu.c~git-parisc +++ a/drivers/parisc/sba_iommu.c @@ -38,22 +38,15 @@ #include #include +#include +#include /* for proc_mckinley_root */ #include /* for proc_runway_root */ #include /* for PDC_MODEL_* */ #include /* for is_pdc_pat() */ #include - -/* declared in arch/parisc/kernel/setup.c */ -extern struct proc_dir_entry * proc_mckinley_root; - #define MODULE_NAME "SBA" -#ifdef CONFIG_PROC_FS -/* depends on proc fs support. But costs CPU performance */ -#undef SBA_COLLECT_STATS -#endif - /* ** The number of debug flags is a clue - this code is fragile. ** Don't even think about messing with it unless you have @@ -92,202 +85,12 @@ extern struct proc_dir_entry * proc_mcki #define DBG_RES(x...) #endif -#if defined(CONFIG_64BIT) -/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ -#define ZX1_SUPPORT -#endif - #define SBA_INLINE __inline__ - -/* -** The number of pdir entries to "free" before issueing -** a read to PCOM register to flush out PCOM writes. -** Interacts with allocation granularity (ie 4 or 8 entries -** allocated and free'd/purged at a time might make this -** less interesting). -*/ -#define DELAYED_RESOURCE_CNT 16 - #define DEFAULT_DMA_HINT_REG 0 -#define ASTRO_RUNWAY_PORT 0x582 -#define IKE_MERCED_PORT 0x803 -#define REO_MERCED_PORT 0x804 -#define REOG_MERCED_PORT 0x805 -#define PLUTO_MCKINLEY_PORT 0x880 - -#define SBA_FUNC_ID 0x0000 /* function id */ -#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ - -#define IS_ASTRO(id) ((id)->hversion == ASTRO_RUNWAY_PORT) -#define IS_IKE(id) ((id)->hversion == IKE_MERCED_PORT) -#define IS_PLUTO(id) ((id)->hversion == PLUTO_MCKINLEY_PORT) - -#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ - -#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE) -#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE) -/* Ike's IOC's occupy functions 2 and 3 */ -#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE) - -#define IOC_CTRL 0x8 /* IOC_CTRL offset */ -#define IOC_CTRL_TC (1 << 0) /* TOC Enable */ -#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */ -#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */ -#define IOC_CTRL_RM (1 << 8) /* Real Mode */ -#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */ -#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */ -#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */ - -#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */ - -#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */ - - -/* -** Offsets into MBIB (Function 0 on Ike and hopefully Astro) -** Firmware programs this stuff. Don't touch it. -*/ -#define LMMIO_DIRECT0_BASE 0x300 -#define LMMIO_DIRECT0_MASK 0x308 -#define LMMIO_DIRECT0_ROUTE 0x310 - -#define LMMIO_DIST_BASE 0x360 -#define LMMIO_DIST_MASK 0x368 -#define LMMIO_DIST_ROUTE 0x370 - -#define IOS_DIST_BASE 0x390 -#define IOS_DIST_MASK 0x398 -#define IOS_DIST_ROUTE 0x3A0 - -#define IOS_DIRECT_BASE 0x3C0 -#define IOS_DIRECT_MASK 0x3C8 -#define IOS_DIRECT_ROUTE 0x3D0 - -/* -** Offsets into I/O TLB (Function 2 and 3 on Ike) -*/ -#define ROPE0_CTL 0x200 /* "regbus pci0" */ -#define ROPE1_CTL 0x208 -#define ROPE2_CTL 0x210 -#define ROPE3_CTL 0x218 -#define ROPE4_CTL 0x220 -#define ROPE5_CTL 0x228 -#define ROPE6_CTL 0x230 -#define ROPE7_CTL 0x238 - -#define IOC_ROPE0_CFG 0x500 /* pluto only */ -#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */ - - - -#define HF_ENABLE 0x40 - - -#define IOC_IBASE 0x300 /* IO TLB */ -#define IOC_IMASK 0x308 -#define IOC_PCOM 0x310 -#define IOC_TCNFG 0x318 -#define IOC_PDIR_BASE 0x320 - -/* AGP GART driver looks for this */ -#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL - - -/* -** IOC supports 4/8/16/64KB page sizes (see TCNFG register) -** It's safer (avoid memory corruption) to keep DMA page mappings -** equivalently sized to VM PAGE_SIZE. -** -** We really can't avoid generating a new mapping for each -** page since the Virtual Coherence Index has to be generated -** and updated for each page. -** -** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse. -*/ -#define IOVP_SIZE PAGE_SIZE -#define IOVP_SHIFT PAGE_SHIFT -#define IOVP_MASK PAGE_MASK - -#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */ -#define SBA_PERF_MASK1 0x718 -#define SBA_PERF_MASK2 0x730 - - -/* -** Offsets into PCI Performance Counters (functions 12 and 13) -** Controlled by PERF registers in function 2 & 3 respectively. -*/ -#define SBA_PERF_CNT1 0x200 -#define SBA_PERF_CNT2 0x208 -#define SBA_PERF_CNT3 0x210 - - -struct ioc { - void __iomem *ioc_hpa; /* I/O MMU base address */ - char *res_map; /* resource map, bit == pdir entry */ - u64 *pdir_base; /* physical base address */ - unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */ - unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */ -#ifdef ZX1_SUPPORT - unsigned long iovp_mask; /* help convert IOVA to IOVP */ -#endif - unsigned long *res_hint; /* next avail IOVP - circular search */ - spinlock_t res_lock; - unsigned int res_bitshift; /* from the LEFT! */ - unsigned int res_size; /* size of resource map in bytes */ -#ifdef SBA_HINT_SUPPORT -/* FIXME : DMA HINTs not used */ - unsigned long hint_mask_pdir; /* bits used for DMA hints */ - unsigned int hint_shift_pdir; -#endif -#if DELAYED_RESOURCE_CNT > 0 - int saved_cnt; - struct sba_dma_pair { - dma_addr_t iova; - size_t size; - } saved[DELAYED_RESOURCE_CNT]; -#endif - -#ifdef SBA_COLLECT_STATS -#define SBA_SEARCH_SAMPLE 0x100 - unsigned long avg_search[SBA_SEARCH_SAMPLE]; - unsigned long avg_idx; /* current index into avg_search */ - unsigned long used_pages; - unsigned long msingle_calls; - unsigned long msingle_pages; - unsigned long msg_calls; - unsigned long msg_pages; - unsigned long usingle_calls; - unsigned long usingle_pages; - unsigned long usg_calls; - unsigned long usg_pages; -#endif - - /* STUFF We don't need in performance path */ - unsigned int pdir_size; /* in bytes, determined by IOV Space size */ -}; - -struct sba_device { - struct sba_device *next; /* list of SBA's in system */ - struct parisc_device *dev; /* dev found in bus walk */ - struct parisc_device_id *iodc; /* data about dev from firmware */ - const char *name; - void __iomem *sba_hpa; /* base address */ - spinlock_t sba_lock; - unsigned int flags; /* state/functionality enabled */ - unsigned int hw_rev; /* HW revision of chip */ - - struct resource chip_resv; /* MMIO reserved for chip */ - struct resource iommu_resv; /* MMIO reserved for iommu */ - - unsigned int num_ioc; /* number of on-board IOC's */ - struct ioc ioc[MAX_IOC]; -}; - - -static struct sba_device *sba_list; +struct sba_device *sba_list; +EXPORT_SYMBOL_GPL(sba_list); static unsigned long ioc_needs_fdc = 0; @@ -300,8 +103,14 @@ static unsigned long piranha_bad_128k = /* Looks nice and keeps the compiler happy */ #define SBA_DEV(d) ((struct sba_device *) (d)) +#ifdef CONFIG_AGP_PARISC +#define SBA_AGP_SUPPORT +#endif /*CONFIG_AGP_PARISC*/ + #ifdef SBA_AGP_SUPPORT -static int reserve_sba_gart = 1; +static int sba_reserve_agpgart = 1; +module_param(sba_reserve_agpgart, int, 1); +MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART"); #endif #define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1)) @@ -741,7 +550,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba)); pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */ - pa |= 0x8000000000000000ULL; /* set "valid" bit */ + pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */ *pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */ /* @@ -1498,6 +1307,10 @@ sba_ioc_init_pluto(struct parisc_device WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM); #ifdef SBA_AGP_SUPPORT +{ + struct klist_iter i; + struct device *dev = NULL; + /* ** If an AGP device is present, only use half of the IOV space ** for PCI DMA. Unfortunately we can't know ahead of time @@ -1506,20 +1319,22 @@ sba_ioc_init_pluto(struct parisc_device ** We program the next pdir index after we stop w/ a key for ** the GART code to handshake on. */ - device=NULL; - for (lba = sba->child; lba; lba = lba->sibling) { + klist_iter_init(&sba->dev.klist_children, &i); + while (dev = next_device(&i)) { + struct parisc_device *lba = to_parisc_device(dev); if (IS_QUICKSILVER(lba)) - break; + agp_found = 1; } + klist_iter_exit(&i); - if (lba) { - DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__); + if (agp_found && sba_reserve_agpgart) { + printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n", + __FUNCTION__, (iova_space_size/2) >> 20); ioc->pdir_size /= 2; - ((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE; - } else { - DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__); + ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE; } -#endif /* 0 */ +} +#endif /*SBA_AGP_SUPPORT*/ } @@ -1701,7 +1516,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x% } #endif - if (!IS_PLUTO(sba_dev->iodc)) { + if (!IS_PLUTO(sba_dev->dev)) { ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL); DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->", __FUNCTION__, sba_dev->sba_hpa, ioc_ctl); @@ -1718,9 +1533,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x% #endif } /* if !PLUTO */ - if (IS_ASTRO(sba_dev->iodc)) { + if (IS_ASTRO(sba_dev->dev)) { int err; - /* PAT_PDC (L-class) also reports the same goofy base */ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET); num_ioc = 1; @@ -1730,13 +1544,9 @@ printk("sba_hw_init(): mem_boot 0x%x 0x% err = request_resource(&iomem_resource, &(sba_dev->chip_resv)); BUG_ON(err < 0); - } else if (IS_PLUTO(sba_dev->iodc)) { + } else if (IS_PLUTO(sba_dev->dev)) { int err; - /* We use a negative value for IOC HPA so it gets - * corrected when we add it with IKE's IOC offset. - * Doesnt look clean, but fewer code. - */ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET); num_ioc = 1; @@ -1752,14 +1562,14 @@ printk("sba_hw_init(): mem_boot 0x%x 0x% err = request_resource(&iomem_resource, &(sba_dev->iommu_resv)); WARN_ON(err < 0); } else { - /* IS_IKE (ie N-class, L3000, L1500) */ + /* IKE, REO */ sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0)); sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1)); num_ioc = 2; /* TODO - LOOKUP Ike/Stretch chipset mem map */ } - /* XXX: What about Reo? */ + /* XXX: What about Reo Grande? */ sba_dev->num_ioc = num_ioc; for (i = 0; i < num_ioc; i++) { @@ -1774,7 +1584,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x% * Overrides bit 1 in DMA Hint Sets. * Improves netperf UDP_STREAM by ~10% for bcm5701. */ - if (IS_PLUTO(sba_dev->iodc)) { + if (IS_PLUTO(sba_dev->dev)) { void __iomem *rope_cfg; unsigned long cfg_val; @@ -1803,7 +1613,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x% READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400) ); - if (IS_PLUTO(sba_dev->iodc)) { + if (IS_PLUTO(sba_dev->dev)) { sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i); } else { sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i); @@ -2067,7 +1877,7 @@ sba_driver_callback(struct parisc_device /* Read HW Rev First */ func_class = READ_REG(sba_addr + SBA_FCLASS); - if (IS_ASTRO(&dev->id)) { + if (IS_ASTRO(dev)) { unsigned long fclass; static char astro_rev[]="Astro ?.?"; @@ -2078,11 +1888,11 @@ sba_driver_callback(struct parisc_device astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3); version = astro_rev; - } else if (IS_IKE(&dev->id)) { + } else if (IS_IKE(dev)) { static char ike_rev[] = "Ike rev ?"; ike_rev[8] = '0' + (char) (func_class & 0xff); version = ike_rev; - } else if (IS_PLUTO(&dev->id)) { + } else if (IS_PLUTO(dev)) { static char pluto_rev[]="Pluto ?.?"; pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4); pluto_rev[8] = '0' + (char) (func_class & 0x0f); @@ -2097,7 +1907,7 @@ sba_driver_callback(struct parisc_device global_ioc_cnt = count_parisc_driver(&sba_driver); /* Astro and Pluto have one IOC per SBA */ - if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id))) + if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev))) global_ioc_cnt *= 2; } @@ -2117,7 +1927,6 @@ sba_driver_callback(struct parisc_device sba_dev->dev = dev; sba_dev->hw_rev = func_class; - sba_dev->iodc = &dev->id; sba_dev->name = dev->name; sba_dev->sba_hpa = sba_addr; diff -puN drivers/serial/8250_gsc.c~git-parisc drivers/serial/8250_gsc.c --- a/drivers/serial/8250_gsc.c~git-parisc +++ a/drivers/serial/8250_gsc.c @@ -22,7 +22,6 @@ #include #include #include -#include /* for LASI_BASE_BAUD */ #include "8250.h" @@ -54,7 +53,8 @@ serial_init_chip(struct parisc_device *d memset(&port, 0, sizeof(port)); port.iotype = UPIO_MEM; - port.uartclk = LASI_BASE_BAUD * 16; + /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */ + port.uartclk = 7272727; port.mapbase = address; port.membase = ioremap_nocache(address, 16); port.irq = dev->irq; diff -puN drivers/serial/Kconfig~git-parisc drivers/serial/Kconfig --- a/drivers/serial/Kconfig~git-parisc +++ a/drivers/serial/Kconfig @@ -556,10 +556,11 @@ config SERIAL_MUX default y ---help--- Saying Y here will enable the hardware MUX serial driver for - the Nova and K class systems. The hardware MUX is not 8250/16550 - compatible therefore the /dev/ttyB0 device is shared between the - Serial MUX and the PDC software console. The following steps - need to be completed to use the Serial MUX: + the Nova, K class systems and D class with a 'remote control card'. + The hardware MUX is not 8250/16550 compatible therefore the + /dev/ttyB0 device is shared between the Serial MUX and the PDC + software console. The following steps need to be completed to use + the Serial MUX: 1. create the device entry (mknod /dev/ttyB0 c 11 0) 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 diff -puN /dev/null include/asm-parisc/agp.h --- /dev/null +++ a/include/asm-parisc/agp.h @@ -0,0 +1,25 @@ +#ifndef _ASM_PARISC_AGP_H +#define _ASM_PARISC_AGP_H + +/* + * PARISC specific AGP definitions. + * Copyright (c) 2006 Kyle McMartin + * + */ + +#define map_page_into_agp(page) /* nothing */ +#define unmap_page_from_agp(page) /* nothing */ +#define flush_agp_mappings() /* nothing */ +#define flush_agp_cache() mb() + +/* Convert a physical address to an address suitable for the GART. */ +#define phys_to_gart(x) (x) +#define gart_to_phys(x) (x) + +/* GATT allocation. Returns/accepts GATT kernel virtual address. */ +#define alloc_gatt_pages(order) \ + ((char *)__get_free_pages(GFP_KERNEL, (order))) +#define free_gatt_pages(table, order) \ + free_pages((unsigned long)(table), (order)) + +#endif /* _ASM_PARISC_AGP_H */ diff -puN include/asm-parisc/assembly.h~git-parisc include/asm-parisc/assembly.h --- a/include/asm-parisc/assembly.h~git-parisc +++ a/include/asm-parisc/assembly.h @@ -29,7 +29,8 @@ #define LDREGX ldd,s #define LDREGM ldd,mb #define STREGM std,ma -#define SHRREG shrd +#define SHRREG shrd +#define SHLREG shld #define RP_OFFSET 16 #define FRAME_SIZE 128 #define CALLEE_REG_FRAME_SIZE 144 @@ -39,7 +40,8 @@ #define LDREGX ldwx,s #define LDREGM ldwm #define STREGM stwm -#define SHRREG shr +#define SHRREG shr +#define SHLREG shlw #define RP_OFFSET 20 #define FRAME_SIZE 64 #define CALLEE_REG_FRAME_SIZE 128 diff -puN include/asm-parisc/cacheflush.h~git-parisc include/asm-parisc/cacheflush.h --- a/include/asm-parisc/cacheflush.h~git-parisc +++ a/include/asm-parisc/cacheflush.h @@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsig } #define ARCH_HAS_FLUSH_ANON_PAGE -static inline void -flush_kernel_dcache_page(struct page *page) +#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE +void flush_kernel_dcache_page_addr(void *addr); +static inline void flush_kernel_dcache_page(struct page *page) { - flush_kernel_dcache_page_asm(page_address(page)); + flush_kernel_dcache_page_addr(page_address(page)); } -#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void); #endif +#ifdef CONFIG_PA8X00 +/* Only pa8800, pa8900 needs this */ +#define ARCH_HAS_KMAP + +void kunmap_parisc(void *addr); + +static inline void *kmap(struct page *page) +{ + might_sleep(); + return page_address(page); +} + +#define kunmap(page) kunmap_parisc(page_address(page)) + +#define kmap_atomic(page, idx) page_address(page) + +#define kunmap_atomic(addr, idx) kunmap_parisc(addr) + +#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn)) +#define kmap_atomic_to_page(ptr) virt_to_page(ptr) +#endif + #endif /* _PARISC_CACHEFLUSH_H */ diff -puN include/asm-parisc/compat.h~git-parisc include/asm-parisc/compat.h --- a/include/asm-parisc/compat.h~git-parisc +++ a/include/asm-parisc/compat.h @@ -5,7 +5,7 @@ */ #include #include -#include +#include #define COMPAT_USER_HZ 100 @@ -152,7 +152,7 @@ static __inline__ void __user *compat_al static inline int __is_compat_task(struct task_struct *t) { - return personality(t->personality) == PER_LINUX32; + return test_ti_thread_flag(t->thread_info, TIF_32BIT); } static inline int is_compat_task(void) diff -puN include/asm-parisc/futex.h~git-parisc include/asm-parisc/futex.h --- a/include/asm-parisc/futex.h~git-parisc +++ a/include/asm-parisc/futex.h @@ -1,6 +1,71 @@ -#ifndef _ASM_FUTEX_H -#define _ASM_FUTEX_H +#ifndef _ASM_PARISC_FUTEX_H +#define _ASM_PARISC_FUTEX_H -#include +#ifdef __KERNEL__ +#include +#include +#include + +static inline int +futex_atomic_op_inuser (int encoded_op, int __user *uaddr) +{ + int op = (encoded_op >> 28) & 7; + int cmp = (encoded_op >> 24) & 15; + int oparg = (encoded_op << 8) >> 20; + int cmparg = (encoded_op << 20) >> 20; + int oldval = 0, ret; + if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28)) + oparg = 1 << oparg; + + if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + inc_preempt_count(); + + switch (op) { + case FUTEX_OP_SET: + case FUTEX_OP_ADD: + case FUTEX_OP_OR: + case FUTEX_OP_ANDN: + case FUTEX_OP_XOR: + default: + ret = -ENOSYS; + } + + dec_preempt_count(); + + if (!ret) { + switch (cmp) { + case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break; + case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break; + case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break; + case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break; + case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break; + case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break; + default: ret = -ENOSYS; + } + } + return ret; +} + +/* Non-atomic version */ +static inline int +futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) +{ + int err = 0; + int uval; + + if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) + return -EFAULT; + + err = get_user(uval, uaddr); + if (err) return -EFAULT; + if (uval == oldval) + err = put_user(newval, uaddr); + if (err) return -EFAULT; + return uval; +} + +#endif #endif diff -puN include/asm-parisc/iosapic.h~git-parisc /dev/null --- a/include/asm-parisc/iosapic.h +++ /dev/null @@ -1,53 +0,0 @@ -/* -** This file is private to iosapic driver. -** If stuff needs to be used by another driver, move it to a common file. -** -** WARNING: fields most data structures here are ordered to make sure -** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8) -*/ - - -/* -** I/O SAPIC init function -** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC. -** Call setup as part of per instance initialization. -** (ie *not* init_module() function unless only one is present.) -** fixup_irq is to initialize PCI IRQ line support and -** virtualize pcidev->irq value. To be called by pci_fixup_bus(). -*/ -extern void *iosapic_register(unsigned long hpa); -extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev); - - -#ifdef __IA64__ -/* -** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter. -** and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field. -** -** IA64: PIB is handled by "Local SAPIC" (integrated in the processor). -*/ -struct local_sapic_info { - struct local_sapic_info *lsi_next; /* point to next CPU info */ - int *lsi_cpu_id; /* point to logical CPU id */ - unsigned long *lsi_id_eid; /* point to IA-64 CPU id */ - int *lsi_status; /* point to CPU status */ - void *lsi_private; /* point to special info */ -}; - -/* -** "root" data structure which ties everything together. -** Should always be able to start with sapic_root and locate -** the desired information. -*/ -struct sapic_info { - struct sapic_info *si_next; /* info is per cell */ - int si_cellid; /* cell id */ - unsigned int si_status; /* status */ - char *si_pib_base; /* intr blk base address */ - local_sapic_info_t *si_local_info; - io_sapic_info_t *si_io_info; - extint_info_t *si_extint_info;/* External Intr info */ -}; - -#endif /* IA64 */ - diff -puN /dev/null include/asm-parisc/irq-handlers.h --- /dev/null +++ a/include/asm-parisc/irq-handlers.h @@ -0,0 +1,15 @@ +HANDLE_LEVEL_IRQ(_chip, cpu_ack_irq, cpu_end_irq) +HANDLE_SPECIFIC_IRQ(_timer, cpu_ack_irq, cpu_end_irq, timer_interrupt) +#ifdef CONFIG_SMP +HANDLE_SPECIFIC_IRQ(_ipi, cpu_ack_irq, cpu_end_irq, ipi_interrupt) +#endif +#ifdef CONFIG_IOSAPIC +HANDLE_LEVEL_IRQ(_iosapic, cpu_ack_irq, iosapic_end_irq) +#endif + +static inline char *arch_handle_irq_name(void fastcall (*handle)(unsigned int, + struct irq_desc *, + struct pt_regs *)) +{ + return NULL; +} diff -puN include/asm-parisc/irq.h~git-parisc include/asm-parisc/irq.h --- a/include/asm-parisc/irq.h~git-parisc +++ a/include/asm-parisc/irq.h @@ -8,6 +8,7 @@ #define _ASM_PARISC_IRQ_H #include +#include #include #define NO_IRQ (-1) @@ -26,12 +27,28 @@ #define NR_IRQS (CPU_IRQ_MAX + 1) +#define ARCH_HAS_IRQ_HANDLERS + +struct irq_desc; + +void fastcall handle_level_irq_chip(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs); +void fastcall handle_level_irq_iosapic(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs); +void fastcall handle_percpu_irq_chip(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs); +void fastcall handle_specific_irq_timer(unsigned int irq, + struct irq_desc *desc, + struct pt_regs *regs); +void fastcall handle_specific_irq_ipi(unsigned int irq, struct irq_desc *desc, + struct pt_regs *regs); + static __inline__ int irq_canonicalize(int irq) { return (irq == 2) ? 9 : irq; } -struct hw_interrupt_type; +struct irq_chip; /* * Some useful "we don't have to do anything here" handlers. Should @@ -39,6 +56,9 @@ struct hw_interrupt_type; */ void no_ack_irq(unsigned int irq); void no_end_irq(unsigned int irq); +void cpu_ack_irq(struct irq_desc *, unsigned int irq); +void cpu_end_irq(struct irq_desc *, unsigned int irq); +void iosapic_end_irq(struct irq_desc *, unsigned int irq); extern int txn_alloc_irq(unsigned int nbits); extern int txn_claim_irq(int); @@ -46,9 +66,13 @@ extern unsigned int txn_alloc_data(unsig extern unsigned long txn_alloc_addr(unsigned int); extern unsigned long txn_affinity_addr(unsigned int irq, int cpu); -extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *); +extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *); extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest); +/* Prototypes for the two directly called interrupts */ +extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *); +extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); + /* soft power switch support (power.c) */ extern struct tasklet_struct power_tasklet; diff -puN /dev/null include/asm-parisc/mckinley.h --- /dev/null +++ a/include/asm-parisc/mckinley.h @@ -0,0 +1,9 @@ +#ifndef ASM_PARISC_MCKINLEY_H +#define ASM_PARISC_MCKINLEY_H +#ifdef __KERNEL__ + +/* declared in arch/parisc/kernel/setup.c */ +extern struct proc_dir_entry * proc_mckinley_root; + +#endif /*__KERNEL__*/ +#endif /*ASM_PARISC_MCKINLEY_H*/ diff -puN include/asm-parisc/page.h~git-parisc include/asm-parisc/page.h --- a/include/asm-parisc/page.h~git-parisc +++ a/include/asm-parisc/page.h @@ -26,24 +26,10 @@ struct page; -extern void purge_kernel_dcache_page(unsigned long); -extern void copy_user_page_asm(void *to, void *from); -extern void clear_user_page_asm(void *page, unsigned long vaddr); - -static inline void -copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg) -{ - copy_user_page_asm(vto, vfrom); - flush_kernel_dcache_page_asm(vto); - /* XXX: ppc flushes icache too, should we? */ -} - -static inline void -clear_user_page(void *page, unsigned long vaddr, struct page *pg) -{ - purge_kernel_dcache_page((unsigned long)page); - clear_user_page_asm(page, vaddr); -} +void copy_user_page_asm(void *to, void *from); +void copy_user_page(void *vto, void *vfrom, unsigned long vaddr, + struct page *pg); +void clear_user_page(void *page, unsigned long vaddr, struct page *pg); /* * These are used to make use of C type-checking.. diff -puN include/asm-parisc/param.h~git-parisc include/asm-parisc/param.h --- a/include/asm-parisc/param.h~git-parisc +++ a/include/asm-parisc/param.h @@ -2,13 +2,9 @@ #define _ASMPARISC_PARAM_H #ifdef __KERNEL__ -# ifdef CONFIG_PA20 -# define HZ 1000 /* Faster machines */ -# else -# define HZ 100 /* Internal kernel timer frequency */ -# endif -# define USER_HZ 100 /* .. some user interfaces are in "ticks" */ -# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ +#define HZ CONFIG_HZ +#define USER_HZ 100 /* some user API use "ticks" */ +#define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #endif #ifndef HZ diff -puN include/asm-parisc/parisc-device.h~git-parisc include/asm-parisc/parisc-device.h --- a/include/asm-parisc/parisc-device.h~git-parisc +++ a/include/asm-parisc/parisc-device.h @@ -1,3 +1,6 @@ +#ifndef _ASM_PARISC_PARISC_DEVICE_H_ +#define _ASM_PARISC_PARISC_DEVICE_H_ + #include struct parisc_device { @@ -57,3 +60,5 @@ parisc_get_drvdata(struct parisc_device } extern struct bus_type parisc_bus_type; + +#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/ diff -puN /dev/null include/asm-parisc/prefetch.h --- /dev/null +++ a/include/asm-parisc/prefetch.h @@ -0,0 +1,39 @@ +/* + * include/asm-parisc/prefetch.h + * + * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book. + * In addition, many implementations do hardware prefetching of both + * instructions and data. + * + * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load + * to gr0 but not in a way that Linux can use. If the load would cause an + * interruption (eg due to prefetching 0), it is suppressed on PA2.0 + * processors, but not on 7300LC. + * + */ + +#ifndef __ASM_PARISC_PREFETCH_H +#define __ASM_PARISC_PREFETCH_H + +#ifndef __ASSEMBLY__ +#ifdef CONFIG_PREFETCH + +#define ARCH_HAS_PREFETCH +extern inline void prefetch(const void *addr) +{ + __asm__("ldw 0(%0), %%r0" : : "r" (addr)); +} + +/* LDD is a PA2.0 addition. */ +#ifdef CONFIG_PA20 +#define ARCH_HAS_PREFETCHW +extern inline void prefetchw(const void *addr) +{ + __asm__("ldd 0(%0), %%r0" : : "r" (addr)); +} +#endif /* CONFIG_PA20 */ + +#endif /* CONFIG_PREFETCH */ +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_PARISC_PROCESSOR_H */ diff -puN include/asm-parisc/processor.h~git-parisc include/asm-parisc/processor.h --- a/include/asm-parisc/processor.h~git-parisc +++ a/include/asm-parisc/processor.h @@ -9,6 +9,8 @@ #define __ASM_PARISC_PROCESSOR_H #ifndef __ASSEMBLY__ +#include /* lockdep.h needs */ + #include #include @@ -276,7 +278,7 @@ on downward growing arches, it looks lik */ #ifdef __LP64__ -#define USER_WIDE_MODE (personality(current->personality) == PER_LINUX) +#define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT)) #else #define USER_WIDE_MODE 0 #endif @@ -328,33 +330,20 @@ extern unsigned long get_wchan(struct ta #define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0]) #define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30]) +#define cpu_relax() barrier() -/* - * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book. - * In addition, many implementations do hardware prefetching of both - * instructions and data. - * - * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load - * to gr0 but not in a way that Linux can use. If the load would cause an - * interruption (eg due to prefetching 0), it is suppressed on PA2.0 - * processors, but not on 7300LC. - */ -#ifdef CONFIG_PREFETCH -#define ARCH_HAS_PREFETCH -#define ARCH_HAS_PREFETCHW - -extern inline void prefetch(const void *addr) -{ - __asm__("ldw 0(%0), %%r0" : : "r" (addr)); -} - -extern inline void prefetchw(const void *addr) +/* Used as a macro to identify the combined VIPT/PIPT cached + * CPUs which require a guarantee of coherency (no inequivalent + * aliases with different data, whether clean or not) to operate */ +static inline int parisc_requires_coherency(void) { - __asm__("ldd 0(%0), %%r0" : : "r" (addr)); -} +#ifdef CONFIG_PA8X00 + /* FIXME: also pa8900 - when we see one */ + return boot_cpu_data.cpu_type == mako; +#else + return 0; #endif - -#define cpu_relax() barrier() +} #endif /* __ASSEMBLY__ */ diff -puN /dev/null include/asm-parisc/ropes.h --- /dev/null +++ a/include/asm-parisc/ropes.h @@ -0,0 +1,322 @@ +#ifndef _ASM_PARISC_ROPES_H_ +#define _ASM_PARISC_ROPES_H_ + +#include + +#ifdef CONFIG_64BIT +/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */ +#define ZX1_SUPPORT +#endif + +#ifdef CONFIG_PROC_FS +/* depends on proc fs support. But costs CPU performance */ +#undef SBA_COLLECT_STATS +#endif + +/* +** The number of pdir entries to "free" before issueing +** a read to PCOM register to flush out PCOM writes. +** Interacts with allocation granularity (ie 4 or 8 entries +** allocated and free'd/purged at a time might make this +** less interesting). +*/ +#define DELAYED_RESOURCE_CNT 16 + +#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */ +#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */ + +struct ioc { + void __iomem *ioc_hpa; /* I/O MMU base address */ + char *res_map; /* resource map, bit == pdir entry */ + u64 *pdir_base; /* physical base address */ + unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */ + unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */ +#ifdef ZX1_SUPPORT + unsigned long iovp_mask; /* help convert IOVA to IOVP */ +#endif + unsigned long *res_hint; /* next avail IOVP - circular search */ + spinlock_t res_lock; + unsigned int res_bitshift; /* from the LEFT! */ + unsigned int res_size; /* size of resource map in bytes */ +#ifdef SBA_HINT_SUPPORT +/* FIXME : DMA HINTs not used */ + unsigned long hint_mask_pdir; /* bits used for DMA hints */ + unsigned int hint_shift_pdir; +#endif +#if DELAYED_RESOURCE_CNT > 0 + int saved_cnt; + struct sba_dma_pair { + dma_addr_t iova; + size_t size; + } saved[DELAYED_RESOURCE_CNT]; +#endif + +#ifdef SBA_COLLECT_STATS +#define SBA_SEARCH_SAMPLE 0x100 + unsigned long avg_search[SBA_SEARCH_SAMPLE]; + unsigned long avg_idx; /* current index into avg_search */ + unsigned long used_pages; + unsigned long msingle_calls; + unsigned long msingle_pages; + unsigned long msg_calls; + unsigned long msg_pages; + unsigned long usingle_calls; + unsigned long usingle_pages; + unsigned long usg_calls; + unsigned long usg_pages; +#endif + /* STUFF We don't need in performance path */ + unsigned int pdir_size; /* in bytes, determined by IOV Space size */ +}; + +struct sba_device { + struct sba_device *next; /* list of SBA's in system */ + struct parisc_device *dev; /* dev found in bus walk */ + const char *name; + void __iomem *sba_hpa; /* base address */ + spinlock_t sba_lock; + unsigned int flags; /* state/functionality enabled */ + unsigned int hw_rev; /* HW revision of chip */ + + struct resource chip_resv; /* MMIO reserved for chip */ + struct resource iommu_resv; /* MMIO reserved for iommu */ + + unsigned int num_ioc; /* number of on-board IOC's */ + struct ioc ioc[MAX_IOC]; +}; + +#define ASTRO_RUNWAY_PORT 0x582 +#define IKE_MERCED_PORT 0x803 +#define REO_MERCED_PORT 0x804 +#define REOG_MERCED_PORT 0x805 +#define PLUTO_MCKINLEY_PORT 0x880 + +static inline int IS_ASTRO(struct parisc_device *d) { + return d->id.hversion == ASTRO_RUNWAY_PORT; +} + +static inline int IS_IKE(struct parisc_device *d) { + return d->id.hversion == IKE_MERCED_PORT; +} + +static inline int IS_PLUTO(struct parisc_device *d) { + return d->id.hversion == PLUTO_MCKINLEY_PORT; +} + +#define PLUTO_IOVA_BASE (1UL*1024*1024*1024) /* 1GB */ +#define PLUTO_IOVA_SIZE (1UL*1024*1024*1024) /* 1GB */ +#define PLUTO_GART_SIZE (PLUTO_IOVA_SIZE / 2) + +#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL + +#define SBA_AGPGART_COOKIE 0x0000badbadc0ffeeULL + +#define SBA_FUNC_ID 0x0000 /* function id */ +#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */ + +#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ + +#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE) +#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE) +/* Ike's IOC's occupy functions 2 and 3 */ +#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE) + +#define IOC_CTRL 0x8 /* IOC_CTRL offset */ +#define IOC_CTRL_TC (1 << 0) /* TOC Enable */ +#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */ +#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */ +#define IOC_CTRL_RM (1 << 8) /* Real Mode */ +#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */ +#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */ +#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */ + +/* +** Offsets into MBIB (Function 0 on Ike and hopefully Astro) +** Firmware programs this stuff. Don't touch it. +*/ +#define LMMIO_DIRECT0_BASE 0x300 +#define LMMIO_DIRECT0_MASK 0x308 +#define LMMIO_DIRECT0_ROUTE 0x310 + +#define LMMIO_DIST_BASE 0x360 +#define LMMIO_DIST_MASK 0x368 +#define LMMIO_DIST_ROUTE 0x370 + +#define IOS_DIST_BASE 0x390 +#define IOS_DIST_MASK 0x398 +#define IOS_DIST_ROUTE 0x3A0 + +#define IOS_DIRECT_BASE 0x3C0 +#define IOS_DIRECT_MASK 0x3C8 +#define IOS_DIRECT_ROUTE 0x3D0 + +/* +** Offsets into I/O TLB (Function 2 and 3 on Ike) +*/ +#define ROPE0_CTL 0x200 /* "regbus pci0" */ +#define ROPE1_CTL 0x208 +#define ROPE2_CTL 0x210 +#define ROPE3_CTL 0x218 +#define ROPE4_CTL 0x220 +#define ROPE5_CTL 0x228 +#define ROPE6_CTL 0x230 +#define ROPE7_CTL 0x238 + +#define IOC_ROPE0_CFG 0x500 /* pluto only */ +#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */ + +#define HF_ENABLE 0x40 + +#define IOC_IBASE 0x300 /* IO TLB */ +#define IOC_IMASK 0x308 +#define IOC_PCOM 0x310 +#define IOC_TCNFG 0x318 +#define IOC_PDIR_BASE 0x320 + +/* +** IOC supports 4/8/16/64KB page sizes (see TCNFG register) +** It's safer (avoid memory corruption) to keep DMA page mappings +** equivalently sized to VM PAGE_SIZE. +** +** We really can't avoid generating a new mapping for each +** page since the Virtual Coherence Index has to be generated +** and updated for each page. +** +** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse. +*/ +#define IOVP_SIZE PAGE_SIZE +#define IOVP_SHIFT PAGE_SHIFT +#define IOVP_MASK PAGE_MASK + +#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */ +#define SBA_PERF_MASK1 0x718 +#define SBA_PERF_MASK2 0x730 + +/* +** Offsets into PCI Performance Counters (functions 12 and 13) +** Controlled by PERF registers in function 2 & 3 respectively. +*/ +#define SBA_PERF_CNT1 0x200 +#define SBA_PERF_CNT2 0x208 +#define SBA_PERF_CNT3 0x210 + +/* +** lba_device: Per instance Elroy data structure +*/ +struct lba_device { + struct pci_hba_data hba; + + spinlock_t lba_lock; + void *iosapic_obj; + +#ifdef CONFIG_64BIT + void __iomem *iop_base; /* PA_VIEW - for IO port accessor funcs */ +#endif + + int flags; /* state/functionality enabled */ + int hw_rev; /* HW revision of chip */ +}; + +#define ELROY_HVERS 0x782 +#define MERCURY_HVERS 0x783 +#define QUICKSILVER_HVERS 0x784 + +static inline int IS_ELROY(struct parisc_device *d) { + return (d->id.hversion == ELROY_HVERS); +} + +static inline int IS_MERCURY(struct parisc_device *d) { + return (d->id.hversion == MERCURY_HVERS); +} + +static inline int IS_QUICKSILVER(struct parisc_device *d) { + return (d->id.hversion == QUICKSILVER_HVERS); +} + +static inline int agp_mode_mercury(void __iomem *hpa) { + u64 bus_mode; + + bus_mode = readl(hpa + 0x0620); + if (bus_mode & 1) + return 1; + + return 0; +} + +/* +** I/O SAPIC init function +** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC. +** Call setup as part of per instance initialization. +** (ie *not* init_module() function unless only one is present.) +** fixup_irq is to initialize PCI IRQ line support and +** virtualize pcidev->irq value. To be called by pci_fixup_bus(). +*/ +extern void *iosapic_register(unsigned long hpa); +extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev); + +#define LBA_FUNC_ID 0x0000 /* function id */ +#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */ +#define LBA_CAPABLE 0x0030 /* capabilities register */ + +#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */ +#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */ + +#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */ +#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */ +#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */ + +#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */ +#define LBA_ARB_PRI 0x0088 /* firmware sets this. */ +#define LBA_ARB_MODE 0x0090 /* firmware sets this. */ +#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */ + +#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */ + +#define LBA_STAT_CTL 0x0108 /* Status & Control */ +#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */ +#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */ +#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */ +#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */ + +#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */ +#define LBA_LMMIO_MASK 0x0208 + +#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */ +#define LBA_GMMIO_MASK 0x0218 + +#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */ +#define LBA_WLMMIO_MASK 0x0228 + +#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */ +#define LBA_WGMMIO_MASK 0x0238 + +#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */ +#define LBA_IOS_MASK 0x0248 + +#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */ +#define LBA_ELMMIO_MASK 0x0258 + +#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */ +#define LBA_EIOS_MASK 0x0268 + +#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */ +#define LBA_DMA_CTL 0x0278 /* firmware sets this */ + +#define LBA_IBASE 0x0300 /* SBA DMA support */ +#define LBA_IMASK 0x0308 + +/* FIXME: ignore DMA Hint stuff until we can measure performance */ +#define LBA_HINT_CFG 0x0310 +#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */ + +#define LBA_BUS_MODE 0x0620 + +/* ERROR regs are needed for config cycle kluges */ +#define LBA_ERROR_CONFIG 0x0680 +#define LBA_SMART_MODE 0x20 +#define LBA_ERROR_STATUS 0x0688 +#define LBA_ROPE_CTL 0x06A0 + +#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */ + +#endif /*_ASM_PARISC_ROPES_H_*/ diff -puN include/asm-parisc/serial.h~git-parisc include/asm-parisc/serial.h --- a/include/asm-parisc/serial.h~git-parisc +++ a/include/asm-parisc/serial.h @@ -3,20 +3,8 @@ */ /* - * This assumes you have a 7.272727 MHz clock for your UART. - * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock - * Clarified: 7.2727MHz on LASI. Not yet clarified for DINO + * This is used for 16550-compatible UARTs */ +#define BASE_BAUD ( 1843200 / 16 ) -#define LASI_BASE_BAUD ( 7272727 / 16 ) -#define BASE_BAUD LASI_BASE_BAUD - -/* - * We don't use the ISA probing code, so these entries are just to reserve - * space. Some example (maximal) configurations: - * - 712 w/ additional Lasi & RJ16 ports: 4 - * - J5k w/ PCI serial cards: 2 + 4 * card ~= 34 - * A500 w/ PCI serial cards: 5 + 4 * card ~= 17 - */ - #define SERIAL_PORT_DFNS diff -puN include/asm-parisc/spinlock.h~git-parisc include/asm-parisc/spinlock.h --- a/include/asm-parisc/spinlock.h~git-parisc +++ a/include/asm-parisc/spinlock.h @@ -56,50 +56,79 @@ static inline int __raw_spin_trylock(raw } /* - * Read-write spinlocks, allowing multiple readers - * but only one writer. + * Read-write spinlocks, allowing multiple readers but only one writer. + * Linux rwlocks are unfair to writers; they can be starved for an indefinite + * time by readers. With care, they can also be taken in interrupt context. + * + * In the PA-RISC implementation, we have a spinlock and a counter. + * Readers use the lock to serialise their access to the counter (which + * records how many readers currently hold the lock). + * Writers hold the spinlock, preventing any readers or other writers from + * grabbing the rwlock. */ -#define __raw_read_trylock(lock) generic__raw_read_trylock(lock) - -/* read_lock, read_unlock are pretty straightforward. Of course it somehow - * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */ - +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock */ static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); - + unsigned long flags; + local_irq_save(flags); + __raw_spin_lock_flags(&rw->lock, flags); rw->counter++; - __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); } +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock */ static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { - __raw_spin_lock(&rw->lock); - + unsigned long flags; + local_irq_save(flags); + __raw_spin_lock_flags(&rw->lock, flags); rw->counter--; - __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); } -/* write_lock is less trivial. We optimistically grab the lock and check - * if we surprised any readers. If so we release the lock and wait till - * they're all gone before trying again - * - * Also note that we don't use the _irqsave / _irqrestore suffixes here. - * If we're called with interrupts enabled and we've got readers (or other - * writers) in interrupt handlers someone fucked up and we'd dead-lock - * sooner or later anyway. prumpf */ +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to grab the same read lock */ +static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) +{ + unsigned long flags; + retry: + local_irq_save(flags); + if (__raw_spin_trylock(&rw->lock)) { + rw->counter++; + __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); + return 1; + } + + local_irq_restore(flags); + /* If write-locked, we fail to acquire the lock */ + if (rw->counter < 0) + return 0; + + /* Wait until we have a realistic chance at the lock */ + while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0) + cpu_relax(); + + goto retry; +} -static __inline__ void __raw_write_lock(raw_rwlock_t *rw) +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to read_trylock() this lock */ +static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { + unsigned long flags; retry: - __raw_spin_lock(&rw->lock); + local_irq_save(flags); + __raw_spin_lock_flags(&rw->lock, flags); - if(rw->counter != 0) { - /* this basically never happens */ + if (rw->counter != 0) { __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); while (rw->counter != 0) cpu_relax(); @@ -107,31 +136,37 @@ retry: goto retry; } - /* got it. now leave without unlocking */ - rw->counter = -1; /* remember we are locked */ + rw->counter = -1; /* mark as write-locked */ + mb(); + local_irq_restore(flags); } -/* write_unlock is absolutely trivial - we don't have to wait for anything */ - -static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) +static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) { rw->counter = 0; __raw_spin_unlock(&rw->lock); } -static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) -{ - __raw_spin_lock(&rw->lock); - if (rw->counter != 0) { - /* this basically never happens */ - __raw_spin_unlock(&rw->lock); - - return 0; +/* Note that we have to ensure interrupts are disabled in case we're + * interrupted by some other code that wants to read_trylock() this lock */ +static __inline__ int __raw_write_trylock(raw_rwlock_t *rw) +{ + unsigned long flags; + int result = 0; + + local_irq_save(flags); + if (__raw_spin_trylock(&rw->lock)) { + if (rw->counter == 0) { + rw->counter = -1; + result = 1; + } else { + /* Read-locked. Oh well. */ + __raw_spin_unlock(&rw->lock); + } } + local_irq_restore(flags); - /* got it. now leave without unlocking */ - rw->counter = -1; /* remember we are locked */ - return 1; + return result; } /* diff -puN include/linux/debug_locks.h~git-parisc include/linux/debug_locks.h --- a/include/linux/debug_locks.h~git-parisc +++ a/include/linux/debug_locks.h @@ -43,6 +43,8 @@ extern int debug_locks_off(void); # define locking_selftest() do { } while (0) #endif +struct task_struct; + #ifdef CONFIG_LOCKDEP extern void debug_show_all_locks(void); extern void debug_show_held_locks(struct task_struct *task); diff -puN include/linux/highmem.h~git-parisc include/linux/highmem.h diff -puN kernel/irq/chip.c~git-parisc kernel/irq/chip.c --- a/kernel/irq/chip.c~git-parisc +++ a/kernel/irq/chip.c @@ -17,6 +17,90 @@ #include "internals.h" +/* Helpers for constructing IRQ handlers */ + +#ifdef CONFIG_SMP +#define HANDLE_PERCPU_IRQ(NAME, ACK, EOI) \ +void fastcall \ +handle_percpu_irq##NAME(unsigned int irq, struct irq_desc *desc, \ + struct pt_regs *regs) \ +{ \ + irqreturn_t action_ret; \ + \ + kstat_this_cpu.irqs[irq]++; \ + \ + ACK(desc, irq); \ + \ + action_ret = handle_IRQ_event(irq, regs, desc->action); \ + if (!noirqdebug) \ + note_interrupt(irq, desc, action_ret, regs); \ + \ + EOI(desc,irq); \ +} +#else +#define HANDLE_PERCPU_IRQ(NAME, ACK, END) +#endif /* CONFIG_SMP */ + +#define HANDLE_LEVEL_IRQ(NAME, MASK, UNMASK) \ +void fastcall \ +handle_level_irq##NAME(unsigned int irq, struct irq_desc *desc, \ + struct pt_regs *regs) \ +{ \ + unsigned int cpu = smp_processor_id(); \ + struct irqaction *action; \ + irqreturn_t action_ret; \ + \ + spin_lock(&desc->lock); \ + MASK(desc, irq); \ + \ + if (unlikely(desc->status & IRQ_INPROGRESS)) \ + goto out; \ + desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); \ + kstat_cpu(cpu).irqs[irq]++; \ + \ + /* \ + * If its disabled or no action available \ + * keep it masked and get out of here \ + */ \ + action = desc->action; \ + if (unlikely(!action || (desc->status & IRQ_DISABLED))) { \ + desc->status |= IRQ_PENDING; \ + goto out; \ + } \ + \ + desc->status |= IRQ_INPROGRESS; \ + desc->status &= ~IRQ_PENDING; \ + spin_unlock(&desc->lock); \ + \ + action_ret = handle_IRQ_event(irq, regs, action); \ + if (!noirqdebug) \ + note_interrupt(irq, desc, action_ret, regs); \ + \ + spin_lock(&desc->lock); \ + desc->status &= ~IRQ_INPROGRESS; \ +out: \ + UNMASK(desc,irq); \ + spin_unlock(&desc->lock); \ +} + +#define HANDLE_SPECIFIC_IRQ(NAME, ACK, EOI, HANDLER) \ +void fastcall \ +handle_specific_irq##NAME(unsigned int irq, struct irq_desc *desc, \ + struct pt_regs *regs) \ +{ \ + irqreturn_t action_ret; \ + \ + kstat_this_cpu.irqs[irq]++; \ + \ + ACK(desc, irq); \ + \ + action_ret = HANDLER(irq, desc->action->dev_id, regs); \ + if (!noirqdebug) \ + note_interrupt(irq, desc, action_ret, regs); \ + \ + EOI(desc,irq); \ +} + /** * set_irq_chip - set the irq chip for an irq * @irq: irq number @@ -186,6 +270,24 @@ static inline void mask_ack_irq(struct i } } +static inline void unmask_enabled_irq(struct irq_desc *desc, int irq) +{ + if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) + desc->chip->unmask(irq); +} + +static inline void ack_irq(struct irq_desc *desc, int irq) +{ + if (desc->chip->ack) + desc->chip->ack(irq); +} + +static inline void eoi_irq(struct irq_desc *desc, int irq) +{ + if (desc->chip->eoi) + desc->chip->eoi(irq); +} + /** * handle_simple_irq - Simple and software-decoded IRQs. * @irq: the interrupt number @@ -241,46 +343,7 @@ out_unlock: * it after the associated handler has acknowledged the device, so the * interrupt line is back to inactive. */ -void fastcall -handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) -{ - unsigned int cpu = smp_processor_id(); - struct irqaction *action; - irqreturn_t action_ret; - - spin_lock(&desc->lock); - mask_ack_irq(desc, irq); - - if (unlikely(desc->status & IRQ_INPROGRESS)) - goto out; - desc->status &= ~(IRQ_REPLAY | IRQ_WAITING); - kstat_cpu(cpu).irqs[irq]++; - - /* - * If its disabled or no action available - * keep it masked and get out of here - */ - action = desc->action; - if (unlikely(!action || (desc->status & IRQ_DISABLED))) { - desc->status |= IRQ_PENDING; - goto out; - } - - desc->status |= IRQ_INPROGRESS; - desc->status &= ~IRQ_PENDING; - spin_unlock(&desc->lock); - - action_ret = handle_IRQ_event(irq, regs, action); - if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); - - spin_lock(&desc->lock); - desc->status &= ~IRQ_INPROGRESS; -out: - if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask) - desc->chip->unmask(irq); - spin_unlock(&desc->lock); -} +HANDLE_LEVEL_IRQ(, mask_ack_irq, unmask_enabled_irq) /** * handle_fasteoi_irq - irq handler for transparent controllers @@ -416,7 +479,6 @@ out_unlock: spin_unlock(&desc->lock); } -#ifdef CONFIG_SMP /** * handle_percpu_IRQ - Per CPU local irq handler * @irq: the interrupt number @@ -425,25 +487,19 @@ out_unlock: * * Per CPU interrupts on SMP machines without locking requirements */ -void fastcall -handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs) -{ - irqreturn_t action_ret; +HANDLE_PERCPU_IRQ(, ack_irq, eoi_irq) - kstat_this_cpu.irqs[irq]++; - - if (desc->chip->ack) - desc->chip->ack(irq); - - action_ret = handle_IRQ_event(irq, regs, desc->action); - if (!noirqdebug) - note_interrupt(irq, desc, action_ret, regs); - - if (desc->chip->eoi) - desc->chip->eoi(irq); +#ifdef ARCH_HAS_IRQ_HANDLERS +#include +#else +static inline char *arch_handle_irq_name(void fastcall (*handle)(unsigned int, + struct irq_desc *, + struct pt_regs *)) +{ + return NULL; } +#endif -#endif /* CONFIG_SMP */ void __set_irq_handler(unsigned int irq, @@ -533,5 +589,5 @@ handle_irq_name(void fastcall (*handle)( if (handle == handle_bad_irq) return "bad "; - return NULL; + return arch_handle_irq_name(handle); } _