From 4068d93cd17561bcbfc821c831cb048385320bd6 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:15:47 -0400 Subject: [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 --- include/asm-parisc/prefetch.h | 36 ++++++++++++++++++++++++++++++++++++ include/asm-parisc/processor.h | 28 ++-------------------------- 2 files changed, 38 insertions(+), 26 deletions(-) create mode 100644 include/asm-parisc/prefetch.h (limited to 'include') diff --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h new file mode 100644 index 000000000000..f5a2e7ae2662 --- /dev/null +++ b/include/asm-parisc/prefetch.h @@ -0,0 +1,36 @@ +/* + * 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)); +} + +#define ARCH_HAS_PREFETCHW +extern inline void prefetchw(const void *addr) +{ + __asm__("ldd 0(%0), %%r0" : : "r" (addr)); +} + +#endif /* CONFIG_PREFETCH */ +#endif /* __ASSEMBLY__ */ + +#endif /* __ASM_PARISC_PROCESSOR_H */ diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index b73626f040da..c72b8fa49686 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -9,6 +9,8 @@ #define __ASM_PARISC_PROCESSOR_H #ifndef __ASSEMBLY__ +#include /* lockdep.h needs */ + #include #include @@ -328,32 +330,6 @@ extern unsigned long get_wchan(struct task_struct *p); #define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0]) #define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30]) - -/* - * 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) -{ - __asm__("ldd 0(%0), %%r0" : : "r" (addr)); -} -#endif - #define cpu_relax() barrier() #endif /* __ASSEMBLY__ */ -- cgit v1.2.3-70-g09d2 From 32104b29cdf93f78ac37e681bd4547413466d13c Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 20:37:26 -0400 Subject: [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 --- arch/parisc/Kconfig | 2 +- include/asm-parisc/prefetch.h | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 6dd0ea8f88e0..d2101237442e 100644 --- a/arch/parisc/Kconfig +++ b/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 --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h index f5a2e7ae2662..5d021726fa33 100644 --- a/include/asm-parisc/prefetch.h +++ b/include/asm-parisc/prefetch.h @@ -24,11 +24,14 @@ 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__ */ -- cgit v1.2.3-70-g09d2 From f86e45131f9d41b1617fbaac7aa1ef23e8d0ab48 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 21:09:31 -0400 Subject: [PATCH] Need forward decl of task_struct in linux/debug_locks.h Signed-off-by: Kyle McMartin --- include/linux/debug_locks.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'include') diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h index 88dafa246d87..952bee79a8f3 100644 --- a/include/linux/debug_locks.h +++ b/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); -- cgit v1.2.3-70-g09d2 From 3d73cf5e18c47d416db4d0734245d3fb087603d9 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:17:19 -0400 Subject: [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 --- arch/parisc/kernel/entry.S | 19 ++++--------------- include/asm-parisc/assembly.h | 6 ++++-- 2 files changed, 8 insertions(+), 17 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 192357a3b9fe..d55b45d54f4d 100644 --- a/arch/parisc/kernel/entry.S +++ b/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 */ @@ -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 --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h index 1a7bfe699e0c..5a1e0e8b1c32 100644 --- a/include/asm-parisc/assembly.h +++ b/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 -- cgit v1.2.3-70-g09d2 From 6f03495d65db4cecc8dc8f2266768f83af0c2710 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:18:57 -0400 Subject: [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 --- drivers/parisc/sba_iommu.c | 5 +---- include/asm-parisc/mckinley.h | 9 +++++++++ 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 include/asm-parisc/mckinley.h (limited to 'include') diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 8b4732815511..d80ce476189f 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -38,15 +38,12 @@ #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 diff --git a/include/asm-parisc/mckinley.h b/include/asm-parisc/mckinley.h new file mode 100644 index 000000000000..d1ea6f12915e --- /dev/null +++ b/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*/ -- cgit v1.2.3-70-g09d2 From 5cfe87d3f543d05a84a509d232330261f1b7bccf Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 13 Aug 2006 22:25:45 -0400 Subject: [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 --- arch/parisc/kernel/irq.c | 2 +- include/asm-parisc/irq.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 5b8803cc3d69..c53bfeb4bf94 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -209,7 +209,7 @@ int show_interrupts(struct seq_file *p, void *v) ** 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; diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h index 5cae260615a2..6e29cfa2812d 100644 --- a/include/asm-parisc/irq.h +++ b/include/asm-parisc/irq.h @@ -31,7 +31,7 @@ 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 @@ -46,7 +46,7 @@ extern unsigned int txn_alloc_data(unsigned int); 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); /* soft power switch support (power.c) */ -- cgit v1.2.3-70-g09d2 From 20f4d3cb9b94ce3fec9a6135b9ad075b82b24f41 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 23 Aug 2006 09:00:04 -0700 Subject: [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 --- arch/parisc/kernel/cache.c | 45 ++++++++++++++++++++++++++++++++++++++++- include/asm-parisc/cacheflush.h | 30 +++++++++++++++++++++++---- include/asm-parisc/page.h | 22 ++++---------------- include/asm-parisc/processor.h | 13 ++++++++++++ 4 files changed, 87 insertions(+), 23 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index bc7c4a4e26a1..7e8d697aef36 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -91,7 +91,8 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte) 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 --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h index 0b459cdfbd6f..2bc41f2e0271 100644 --- a/include/asm-parisc/cacheflush.h +++ b/include/asm-parisc/cacheflush.h @@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsigned long vmaddr) } #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 --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h index 57d6d82756dd..3567208191e3 100644 --- a/include/asm-parisc/page.h +++ b/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 --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index c72b8fa49686..4313618c98ee 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -332,6 +332,19 @@ extern unsigned long get_wchan(struct task_struct *p); #define cpu_relax() barrier() +/* 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) +{ +#ifdef CONFIG_PA8X00 + /* FIXME: also pa8900 - when we see one */ + return boot_cpu_data.cpu_type == mako; +#else + return 0; +#endif +} + #endif /* __ASSEMBLY__ */ #endif /* __ASM_PARISC_PROCESSOR_H */ -- cgit v1.2.3-70-g09d2 From 8f611c453c6a41eee73645c80ccb10493e74b630 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sat, 16 Sep 2006 14:38:22 -0400 Subject: [PARISC] Prevent multiple includes of asm-parisc/parisc-device.h Signed-off-by: Kyle McMartin --- include/asm-parisc/parisc-device.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h index 1d247e32a608..e12624d8941d 100644 --- a/include/asm-parisc/parisc-device.h +++ b/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 *d) } extern struct bus_type parisc_bus_type; + +#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/ -- cgit v1.2.3-70-g09d2 From df570b9c284701d08b22aa00cbfcf870b7f1b7c1 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Sun, 27 Aug 2006 11:04:26 -0400 Subject: [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 --- arch/parisc/kernel/binfmt_elf32.c | 24 +----------------------- arch/parisc/kernel/signal.c | 5 ++--- include/asm-parisc/compat.h | 4 ++-- include/asm-parisc/processor.h | 2 +- 4 files changed, 6 insertions(+), 29 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c index d1833f164bbe..1e64e7b88110 100644 --- a/arch/parisc/kernel/binfmt_elf32.c +++ b/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_t cputime, struct compat_timeval *value) } #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 --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index bb83880c5ee3..ee6653edeb7a 100644 --- a/arch/parisc/kernel/signal.c +++ b/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_sigaction *ka, siginfo_t *info, 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 --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h index 71b4eeea205a..fe8579023531 100644 --- a/include/asm-parisc/compat.h +++ b/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_alloc_user_space(long len) 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 --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h index 4313618c98ee..fd7866dc8c83 100644 --- a/include/asm-parisc/processor.h +++ b/include/asm-parisc/processor.h @@ -278,7 +278,7 @@ on downward growing arches, it looks like this: */ #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 -- cgit v1.2.3-70-g09d2 From 136ce40e9f1f24ca1dbf7714c669a7bca56440ea Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Mon, 28 Aug 2006 11:53:30 -0600 Subject: [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 --- drivers/serial/8250_gsc.c | 4 ++-- include/asm-parisc/serial.h | 16 ++-------------- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'include') diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index 1ebe6b585d2d..c5d0addfda4f 100644 --- a/drivers/serial/8250_gsc.c +++ b/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 *dev) 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 --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h index 82fd820d684f..d7e3cc60dbc3 100644 --- a/include/asm-parisc/serial.h +++ b/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 -- cgit v1.2.3-70-g09d2 From 6e071852a10ec02570c472052f07b5facb5ad857 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Sat, 2 Sep 2006 07:54:58 -0600 Subject: [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 --- include/asm-parisc/spinlock.h | 98 +++++++++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 37 deletions(-) (limited to 'include') diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index e1825530365d..8980a876cc4e 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -56,50 +56,70 @@ static inline int __raw_spin_trylock(raw_spinlock_t *x) } /* - * Read-write spinlocks, allowing multiple readers - * but only one writer. + * Read-write spinlocks, allowing multiple readers but only one writer. + * The spinlock is held by the writer, preventing any readers or other + * writers from grabbing the rwlock. Readers use the lock to serialise their + * access to the counter (which records how many readers currently hold the + * lock). Linux rwlocks are unfair to writers; they can be starved for + * an indefinite time by readers. They can also be taken in interrupt context, + * so we have to disable interrupts when acquiring the spin lock to be sure + * that an interrupting reader doesn't get an inconsistent view of the lock. */ -#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. */ - static __inline__ void __raw_read_lock(raw_rwlock_t *rw) { + unsigned long flags; + local_irq_save(flags); __raw_spin_lock(&rw->lock); - rw->counter++; - __raw_spin_unlock(&rw->lock); + local_irq_restore(flags); } static __inline__ void __raw_read_unlock(raw_rwlock_t *rw) { + unsigned long flags; + local_irq_save(flags); __raw_spin_lock(&rw->lock); - 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 */ +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) +static __inline__ void __raw_write_lock(raw_rwlock_t *rw) { + unsigned long flags; retry: + local_irq_save(flags); __raw_spin_lock(&rw->lock); - 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 +127,35 @@ 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) +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; + 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; } /* -- cgit v1.2.3-70-g09d2 From 342a0497c23c278633f8674ab62f71e5049b7080 Mon Sep 17 00:00:00 2001 From: Carlos O'Donell Date: Thu, 7 Sep 2006 13:05:17 -0400 Subject: [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 --- include/asm-parisc/futex.h | 71 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h index 6a332a9f099c..d84bbb283fd1 100644 --- a/include/asm-parisc/futex.h +++ b/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 -- cgit v1.2.3-70-g09d2 From 9cf8f370f0777a24808b3485f3b5abb8e736d3e8 Mon Sep 17 00:00:00 2001 From: Grant Grundler Date: Fri, 1 Sep 2006 14:50:25 -0700 Subject: [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 --- include/asm-parisc/param.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/asm-parisc/param.h b/include/asm-parisc/param.h index 07cb9b93cfe2..32e03d877858 100644 --- a/include/asm-parisc/param.h +++ b/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 -- cgit v1.2.3-70-g09d2 From 65ee8f0a7fc2f2267b983f1f0349acb8f19db6e6 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Fri, 8 Sep 2006 05:43:44 -0600 Subject: [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 --- include/asm-parisc/spinlock.h | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h index 8980a876cc4e..f3d2090a18dc 100644 --- a/include/asm-parisc/spinlock.h +++ b/include/asm-parisc/spinlock.h @@ -57,35 +57,42 @@ static inline int __raw_spin_trylock(raw_spinlock_t *x) /* * Read-write spinlocks, allowing multiple readers but only one writer. - * The spinlock is held by the writer, preventing any readers or other - * writers from grabbing the rwlock. Readers use the lock to serialise their - * access to the counter (which records how many readers currently hold the - * lock). Linux rwlocks are unfair to writers; they can be starved for - * an indefinite time by readers. They can also be taken in interrupt context, - * so we have to disable interrupts when acquiring the spin lock to be sure - * that an interrupting reader doesn't get an inconsistent view of the lock. + * 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. */ +/* 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) { unsigned long flags; local_irq_save(flags); - __raw_spin_lock(&rw->lock); + __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) { unsigned long flags; local_irq_save(flags); - __raw_spin_lock(&rw->lock); + __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__ int __raw_read_trylock(raw_rwlock_t *rw) { unsigned long flags; @@ -110,12 +117,14 @@ static __inline__ int __raw_read_trylock(raw_rwlock_t *rw) goto retry; } +/* 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: local_irq_save(flags); - __raw_spin_lock(&rw->lock); + __raw_spin_lock_flags(&rw->lock, flags); if (rw->counter != 0) { __raw_spin_unlock(&rw->lock); @@ -138,6 +147,8 @@ static __inline__ void __raw_write_unlock(raw_rwlock_t *rw) __raw_spin_unlock(&rw->lock); } +/* 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; -- cgit v1.2.3-70-g09d2 From 7085689ed135f94108e46c372015c6f5cd3372a3 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 9 Sep 2006 12:36:25 -0700 Subject: [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 --- arch/parisc/kernel/irq.c | 149 +++++++++++++++++++++++++++-------------------- arch/parisc/kernel/smp.c | 3 + drivers/parisc/iosapic.c | 3 +- include/asm-parisc/irq.h | 2 + 4 files changed, 93 insertions(+), 64 deletions(-) (limited to 'include') diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index c53bfeb4bf94..9bdd0197ceb7 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -45,6 +45,17 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *); */ 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 +73,6 @@ static void cpu_enable_irq(unsigned int irq) 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 +88,45 @@ static unsigned int cpu_startup_irq(unsigned int irq) void no_ack_irq(unsigned int irq) { } void no_end_irq(unsigned int irq) { } +void cpu_ack_irq(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(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 +155,8 @@ static struct hw_interrupt_type cpu_interrupt_type = { .shutdown = cpu_disable_irq, .enable = cpu_enable_irq, .disable = cpu_disable_irq, - .ack = no_ack_irq, - .end = no_end_irq, + .ack = cpu_ack_irq, + .end = cpu_end_irq, #ifdef CONFIG_SMP .set_affinity = cpu_set_affinity_irq, #endif @@ -298,82 +334,69 @@ unsigned int txn_alloc_data(unsigned int virt_irq) 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 + __do_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 diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c index f33e8de438dc..faad338f310e 100644 --- a/arch/parisc/kernel/smp.c +++ b/arch/parisc/kernel/smp.c @@ -262,6 +262,9 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs) this_cpu, which); return IRQ_NONE; } /* Switch */ + /* let in any pending interrupts */ + local_irq_enable(); + local_irq_disable(); } /* while (ops) */ } return IRQ_HANDLED; diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 1fbda77cefc2..90489ade632e 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -692,6 +692,7 @@ static void iosapic_end_irq(unsigned int 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(irq); } static unsigned int iosapic_startup_irq(unsigned int irq) @@ -728,7 +729,7 @@ static struct hw_interrupt_type iosapic_interrupt_type = { .shutdown = iosapic_disable_irq, .enable = iosapic_enable_irq, .disable = iosapic_disable_irq, - .ack = no_ack_irq, + .ack = cpu_ack_irq, .end = iosapic_end_irq, #ifdef CONFIG_SMP .set_affinity = iosapic_set_affinity_irq, diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h index 6e29cfa2812d..399c81981ed5 100644 --- a/include/asm-parisc/irq.h +++ b/include/asm-parisc/irq.h @@ -39,6 +39,8 @@ struct irq_chip; */ void no_ack_irq(unsigned int irq); void no_end_irq(unsigned int irq); +void cpu_ack_irq(unsigned int irq); +void cpu_end_irq(unsigned int irq); extern int txn_alloc_irq(unsigned int nbits); extern int txn_claim_irq(int); -- cgit v1.2.3-70-g09d2 From 1790cf9111f61d360d861901b97eba4de3b5414c Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 24 Aug 2006 21:32:49 -0400 Subject: [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 --- drivers/parisc/iosapic.c | 2 +- drivers/parisc/lba_pci.c | 40 +----------- drivers/parisc/sba_iommu.c | 109 +------------------------------ include/asm-parisc/iosapic.h | 53 --------------- include/asm-parisc/ropes.h | 150 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 153 insertions(+), 201 deletions(-) delete mode 100644 include/asm-parisc/iosapic.h create mode 100644 include/asm-parisc/ropes.h (limited to 'include') diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c index 90489ade632e..c2949b4367e5 100644 --- a/drivers/parisc/iosapic.c +++ b/drivers/parisc/iosapic.c @@ -146,7 +146,7 @@ #include #endif -#include +#include #include "./iosapic_private.h" #define MODULE_NAME "iosapic" diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index a596dbc804a3..98f03686a710 100644 --- a/drivers/parisc/lba_pci.c +++ b/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 */ @@ -169,44 +169,6 @@ #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 */ diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 5fbc11e4bc5d..12776b7e3a84 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -38,6 +38,7 @@ #include #include +#include #include /* for proc_mckinley_root */ #include /* for proc_runway_root */ #include /* for PDC_MODEL_* */ @@ -46,11 +47,6 @@ #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 @@ -89,46 +85,13 @@ #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... */ -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 SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */ #define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE) @@ -145,10 +108,6 @@ static inline int IS_PLUTO(struct parisc_device *d) { #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) @@ -196,9 +155,6 @@ static inline int IS_PLUTO(struct parisc_device *d) { #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) @@ -228,69 +184,6 @@ static inline int IS_PLUTO(struct parisc_device *d) { #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 */ - 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; static unsigned long ioc_needs_fdc = 0; diff --git a/include/asm-parisc/iosapic.h b/include/asm-parisc/iosapic.h deleted file mode 100644 index 613390e6805c..000000000000 --- 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 --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h new file mode 100644 index 000000000000..413dfcca15c7 --- /dev/null +++ b/include/asm-parisc/ropes.h @@ -0,0 +1,150 @@ +#ifndef _ASM_PARISC_ROPES_H_ +#define _ASM_PARISC_ROPES_H_ + +#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 SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL + +/* +** 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); +} + +/* +** 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); + +#endif /*_ASM_PARISC_ROPES_H_*/ -- cgit v1.2.3-70-g09d2 From 983daeec99f07fca0a8a9180ba1ca65bbd40c820 Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Fri, 25 Aug 2006 12:28:24 -0400 Subject: [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 --- drivers/parisc/lba_pci.c | 65 ------------------ drivers/parisc/sba_iommu.c | 97 +-------------------------- include/asm-parisc/ropes.h | 162 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 162 insertions(+), 162 deletions(-) (limited to 'include') diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 98f03686a710..ba6769934c77 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -100,71 +100,6 @@ #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; diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index 12776b7e3a84..eed99bdcfb6b 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -89,101 +89,6 @@ #define DEFAULT_DMA_HINT_REG 0 -#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 - static struct sba_device *sba_list; static unsigned long ioc_needs_fdc = 0; @@ -638,7 +543,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba, 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 */ /* diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h index 413dfcca15c7..2e3de0ae04d1 100644 --- a/include/asm-parisc/ropes.h +++ b/include/asm-parisc/ropes.h @@ -101,7 +101,102 @@ static inline int IS_PLUTO(struct parisc_device *d) { return d->id.hversion == PLUTO_MCKINLEY_PORT; } -#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL +#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 @@ -147,4 +242,69 @@ static inline int IS_QUICKSILVER(struct parisc_device *d) { 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_*/ -- cgit v1.2.3-70-g09d2 From 08a6436816f7a16113c73be767ee8d50440e494e Mon Sep 17 00:00:00 2001 From: Kyle McMartin Date: Thu, 24 Aug 2006 21:33:40 -0400 Subject: [PARISC] Add support for Quicksilver AGPGART Signed-off-by: Kyle McMartin --- drivers/char/agp/Kconfig | 10 +- drivers/char/agp/Makefile | 1 + drivers/char/agp/parisc-agp.c | 416 ++++++++++++++++++++++++++++++++++++++++++ drivers/parisc/sba_iommu.c | 35 ++-- include/asm-parisc/agp.h | 25 +++ include/asm-parisc/ropes.h | 12 ++ 6 files changed, 487 insertions(+), 12 deletions(-) create mode 100644 drivers/char/agp/parisc-agp.c create mode 100644 include/asm-parisc/agp.h (limited to 'include') diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig index 22f8cf218cc6..c603bf291580 100644 --- a/drivers/char/agp/Kconfig +++ b/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 @@ -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 --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile index d33a22f2fa0b..3e581603d0a8 100644 --- a/drivers/char/agp/Makefile +++ b/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 --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c new file mode 100644 index 000000000000..17c50b0f83f0 --- /dev/null +++ b/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 --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index eed99bdcfb6b..294c1117098d 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -89,7 +89,8 @@ #define DEFAULT_DMA_HINT_REG 0 -static struct sba_device *sba_list; +struct sba_device *sba_list; +EXPORT_SYMBOL_GPL(sba_list); static unsigned long ioc_needs_fdc = 0; @@ -102,8 +103,14 @@ static unsigned long piranha_bad_128k = 0; /* 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)) @@ -1300,6 +1307,10 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) 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 @@ -1308,20 +1319,22 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num) ** 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(&sba->dev.klist_children, &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*/ } diff --git a/include/asm-parisc/agp.h b/include/asm-parisc/agp.h new file mode 100644 index 000000000000..9f61d4eb6c01 --- /dev/null +++ b/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 --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h index 2e3de0ae04d1..5542dd00472b 100644 --- a/include/asm-parisc/ropes.h +++ b/include/asm-parisc/ropes.h @@ -1,6 +1,8 @@ #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 @@ -231,6 +233,16 @@ 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. -- cgit v1.2.3-70-g09d2 From 01232e932988fcf6ad87be49f69e633dd652a46d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 19 Sep 2006 16:37:01 -0600 Subject: [PARISC] Fix iounmap compile warning iounmap's argument needs to be both const and volatile, otherwise we'll get warnings that we're discarding pointer qualifiers Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- arch/parisc/mm/ioremap.c | 2 +- include/asm-parisc/io.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c index 27384567a1d0..47a1d2ac9419 100644 --- a/arch/parisc/mm/ioremap.c +++ b/arch/parisc/mm/ioremap.c @@ -188,7 +188,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l } EXPORT_SYMBOL(__ioremap); -void iounmap(void __iomem *addr) +void iounmap(const volatile void __iomem *addr) { if (addr > high_memory) return vfree((void *) (PAGE_MASK & (unsigned long __force) addr)); diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h index b9eb245b8874..c1963ce19dd2 100644 --- a/include/asm-parisc/io.h +++ b/include/asm-parisc/io.h @@ -134,7 +134,7 @@ extern inline void __iomem * ioremap(unsigned long offset, unsigned long size) } #define ioremap_nocache(off, sz) ioremap((off), (sz)) -extern void iounmap(void __iomem *addr); +extern void iounmap(const volatile void __iomem *addr); static inline unsigned char __raw_readb(const volatile void __iomem *addr) { -- cgit v1.2.3-70-g09d2 From f312094556619aed849862089938c14aa6a5b84b Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 19 Sep 2006 19:37:09 -0600 Subject: [PARISC] Define pci_get_legacy_ide_irq We can compile at least one IDE driver that refers to this. We can't use the asm-generic file because we have our own definitions of pcibios_resource_to_bus etc. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- include/asm-parisc/pci.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'include') diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h index 8b631f47eb25..7b8ad118d2fe 100644 --- a/include/asm-parisc/pci.h +++ b/include/asm-parisc/pci.h @@ -293,4 +293,9 @@ static inline void pcibios_penalize_isa_irq(int irq, int active) /* We don't need to penalize isa irq's */ } +static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) +{ + return channel ? 15 : 14; +} + #endif /* __ASM_PARISC_PCI_H */ -- cgit v1.2.3-70-g09d2 From 99b6e9be71b9ad2c50c0d160b5af18848fee466d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 20 Sep 2006 20:36:42 -0600 Subject: [PARISC] Make DMA routines more stubby We were pretending to use the GENERIC_ISA_DMA routines, but never selected that symbol. Since ISA DMA is known to not work right now, just remove the attempts to acquire the dma_spin_lock to fix compile warnings. Signed-off-by: Matthew Wilcox Signed-off-by: Kyle McMartin --- include/asm-parisc/dma.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'include') diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h index 9979c3cb3745..da2cf373e31c 100644 --- a/include/asm-parisc/dma.h +++ b/include/asm-parisc/dma.h @@ -72,18 +72,13 @@ #define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ #define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG) -extern spinlock_t dma_spin_lock; - static __inline__ unsigned long claim_dma_lock(void) { - unsigned long flags; - spin_lock_irqsave(&dma_spin_lock, flags); - return flags; + return 0; } static __inline__ void release_dma_lock(unsigned long flags) { - spin_unlock_irqrestore(&dma_spin_lock, flags); } -- cgit v1.2.3-70-g09d2