From a34a9b9682a5a9de53386ed0872c7d38ca9d6b38 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 19 Jun 2018 09:04:53 +0200 Subject: [PATCH 1/9] parisc: merge pcx_dma_ops and pcxl_dma_ops The only difference is that pcxl supports dma coherent allocations, while pcx only supports non-consistent allocations and otherwise fails. But dma_alloc* is not in the fast path, and merging these two allows an easy migration path to the generic dma-noncoherent implementation, so do it. Signed-off-by: Christoph Hellwig Signed-off-by: Helge Deller --- arch/parisc/include/asm/dma-mapping.h | 3 +- arch/parisc/kernel/pci-dma.c | 80 ++++++++++++--------------- arch/parisc/kernel/setup.c | 8 +-- arch/parisc/mm/init.c | 11 +--- 4 files changed, 43 insertions(+), 59 deletions(-) diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index 01e1fc057c83..eeec8dd18e74 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -22,8 +22,7 @@ */ #ifdef CONFIG_PA11 -extern const struct dma_map_ops pcxl_dma_ops; -extern const struct dma_map_ops pcx_dma_ops; +extern const struct dma_map_ops pa11_dma_ops; #endif extern const struct dma_map_ops *hppa_dma_ops; diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index 6df07ce4f3c2..d34cd6d34717 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -395,7 +395,7 @@ pcxl_dma_init(void) __initcall(pcxl_dma_init); -static void *pa11_dma_alloc(struct device *dev, size_t size, +static void *pcxl_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) { unsigned long vaddr; @@ -422,16 +422,44 @@ static void *pa11_dma_alloc(struct device *dev, size_t size, return (void *)vaddr; } +static void *pcx_dma_alloc(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) +{ + void *addr; + + if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) + return NULL; + + addr = (void *)__get_free_pages(flag, get_order(size)); + if (addr) + *dma_handle = (dma_addr_t)virt_to_phys(addr); + + return addr; +} + +static void *pa11_dma_alloc(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) +{ + + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) + return pcxl_dma_alloc(dev, size, dma_handle, gfp, attrs); + else + return pcx_dma_alloc(dev, size, dma_handle, gfp, attrs); +} + static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { - int order; + int order = get_order(size); - order = get_order(size); - size = 1 << (order + PAGE_SHIFT); - unmap_uncached_pages((unsigned long)vaddr, size); - pcxl_free_range((unsigned long)vaddr, size); - free_pages((unsigned long)__va(dma_handle), order); + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { + size = 1 << (order + PAGE_SHIFT); + unmap_uncached_pages((unsigned long)vaddr, size); + pcxl_free_range((unsigned long)vaddr, size); + + vaddr = __va(dma_handle); + } + free_pages((unsigned long)vaddr, get_order(size)); } static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, @@ -560,7 +588,7 @@ static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, flush_kernel_dcache_range((unsigned long)vaddr, size); } -const struct dma_map_ops pcxl_dma_ops = { +const struct dma_map_ops pa11_dma_ops = { .alloc = pa11_dma_alloc, .free = pa11_dma_free, .map_page = pa11_dma_map_page, @@ -573,39 +601,3 @@ const struct dma_map_ops pcxl_dma_ops = { .sync_sg_for_device = pa11_dma_sync_sg_for_device, .cache_sync = pa11_dma_cache_sync, }; - -static void *pcx_dma_alloc(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, unsigned long attrs) -{ - void *addr; - - if ((attrs & DMA_ATTR_NON_CONSISTENT) == 0) - return NULL; - - addr = (void *)__get_free_pages(flag, get_order(size)); - if (addr) - *dma_handle = (dma_addr_t)virt_to_phys(addr); - - return addr; -} - -static void pcx_dma_free(struct device *dev, size_t size, void *vaddr, - dma_addr_t iova, unsigned long attrs) -{ - free_pages((unsigned long)vaddr, get_order(size)); - return; -} - -const struct dma_map_ops pcx_dma_ops = { - .alloc = pcx_dma_alloc, - .free = pcx_dma_free, - .map_page = pa11_dma_map_page, - .unmap_page = pa11_dma_unmap_page, - .map_sg = pa11_dma_map_sg, - .unmap_sg = pa11_dma_unmap_sg, - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, - .sync_single_for_device = pa11_dma_sync_single_for_device, - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, - .sync_sg_for_device = pa11_dma_sync_sg_for_device, - .cache_sync = pa11_dma_cache_sync, -}; diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 8d3a7b80ac42..5c8450a22255 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -97,14 +97,12 @@ void __init dma_ops_init(void) panic( "PA-RISC Linux currently only supports machines that conform to\n" "the PA-RISC 1.1 or 2.0 architecture specification.\n"); - case pcxs: - case pcxt: - hppa_dma_ops = &pcx_dma_ops; - break; case pcxl2: pa7300lc_init(); case pcxl: /* falls through */ - hppa_dma_ops = &pcxl_dma_ops; + case pcxs: + case pcxt: + hppa_dma_ops = &pa11_dma_ops; break; default: break; diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c index 2607d2d33405..74842d28a7a1 100644 --- a/arch/parisc/mm/init.c +++ b/arch/parisc/mm/init.c @@ -19,7 +19,6 @@ #include #include #include -#include /* for hppa_dma_ops and pcxl_dma_ops */ #include #include #include @@ -616,17 +615,13 @@ void __init mem_init(void) free_all_bootmem(); #ifdef CONFIG_PA11 - if (hppa_dma_ops == &pcxl_dma_ops) { + if (boot_cpu_data.cpu_type == pcxl2 || boot_cpu_data.cpu_type == pcxl) { pcxl_dma_start = (unsigned long)SET_MAP_OFFSET(MAP_START); parisc_vmalloc_start = SET_MAP_OFFSET(pcxl_dma_start + PCXL_DMA_MAP_SIZE); - } else { - pcxl_dma_start = 0; - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); - } -#else - parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); + } else #endif + parisc_vmalloc_start = SET_MAP_OFFSET(MAP_START); mem_init_print_info(NULL); From 7f1501053811414ddeff63db8f5d41bdbe38068f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 19 Jun 2018 09:04:54 +0200 Subject: [PATCH 2/9] parisc: always use flush_kernel_dcache_range for DMA cache maintainance Current the S/G list based DMA ops use flush_kernel_vmap_range which contains a few UP optimizations, while the rest of the DMA operations uses flush_kernel_dcache_range. The single vs sg operations are supposed to have the same effect, so they should use the same routines. Use the more conservation version for now, but if people more familiar with parisc think the vmap version is generally fine for DMA we should switch all interfaces over to it. Signed-off-by: Christoph Hellwig Signed-off-by: Helge Deller --- arch/parisc/kernel/pci-dma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index d34cd6d34717..1f85ca2c0c9e 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -537,7 +537,7 @@ static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ for_each_sg(sglist, sg, nents, i) - flush_kernel_vmap_range(sg_virt(sg), sg->length); + flush_kernel_dcache_range(sg_virt(sg), sg->length); } static void pa11_dma_sync_single_for_cpu(struct device *dev, @@ -568,7 +568,7 @@ static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sgl /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ for_each_sg(sglist, sg, nents, i) - flush_kernel_vmap_range(sg_virt(sg), sg->length); + flush_kernel_dcache_range(sg_virt(sg), sg->length); } static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) @@ -579,7 +579,7 @@ static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist * /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ for_each_sg(sglist, sg, nents, i) - flush_kernel_vmap_range(sg_virt(sg), sg->length); + flush_kernel_dcache_range(sg_virt(sg), sg->length); } static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, From c1f59375b3782f478ac2c488889abdc00dd8e25f Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 19 Jun 2018 09:04:55 +0200 Subject: [PATCH 3/9] parisc: use generic dma_noncoherent_ops Switch to the generic noncoherent direct mapping implementation. Fix sync_single_for_cpu to do skip the cache flush unless the transfer is to the device to match the more tested unmap_single path which should have the same cache coherency implications. Signed-off-by: Christoph Hellwig Signed-off-by: Helge Deller --- arch/parisc/Kconfig | 4 + arch/parisc/include/asm/dma-mapping.h | 4 - arch/parisc/kernel/pci-dma.c | 145 ++------------------------ arch/parisc/kernel/setup.c | 2 +- 4 files changed, 16 insertions(+), 139 deletions(-) diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index e7705dde953f..1fcdf1565b23 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -187,6 +187,10 @@ config PA20 config PA11 def_bool y depends on PA7000 || PA7100LC || PA7200 || PA7300LC + select ARCH_HAS_SYNC_DMA_FOR_CPU + select ARCH_HAS_SYNC_DMA_FOR_DEVICE + select DMA_NONCOHERENT_OPS + select DMA_NONCOHERENT_CACHE_SYNC config PREFETCH def_bool y diff --git a/arch/parisc/include/asm/dma-mapping.h b/arch/parisc/include/asm/dma-mapping.h index eeec8dd18e74..44a9f97194aa 100644 --- a/arch/parisc/include/asm/dma-mapping.h +++ b/arch/parisc/include/asm/dma-mapping.h @@ -21,10 +21,6 @@ ** flush/purge and allocate "regular" cacheable pages for everything. */ -#ifdef CONFIG_PA11 -extern const struct dma_map_ops pa11_dma_ops; -#endif - extern const struct dma_map_ops *hppa_dma_ops; static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index 1f85ca2c0c9e..04c48f1ef3fb 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -21,13 +21,12 @@ #include #include #include -#include #include #include #include #include -#include -#include +#include +#include #include #include /* for DMA_CHUNK_SIZE */ @@ -437,7 +436,7 @@ static void *pcx_dma_alloc(struct device *dev, size_t size, return addr; } -static void *pa11_dma_alloc(struct device *dev, size_t size, +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs) { @@ -447,7 +446,7 @@ static void *pa11_dma_alloc(struct device *dev, size_t size, return pcx_dma_alloc(dev, size, dma_handle, gfp, attrs); } -static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, +void arch_dma_free(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, unsigned long attrs) { int order = get_order(size); @@ -462,142 +461,20 @@ static void pa11_dma_free(struct device *dev, size_t size, void *vaddr, free_pages((unsigned long)vaddr, get_order(size)); } -static dma_addr_t pa11_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction, unsigned long attrs) +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr, + size_t size, enum dma_data_direction dir) { - void *addr = page_address(page) + offset; - BUG_ON(direction == DMA_NONE); - - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) - flush_kernel_dcache_range((unsigned long) addr, size); - - return virt_to_phys(addr); + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); } -static void pa11_dma_unmap_page(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction direction, - unsigned long attrs) +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr, + size_t size, enum dma_data_direction dir) { - BUG_ON(direction == DMA_NONE); - - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - return; - - if (direction == DMA_TO_DEVICE) - return; - - /* - * For PCI_DMA_FROMDEVICE this flush is not necessary for the - * simple map/unmap case. However, it IS necessary if if - * pci_dma_sync_single_* has been called and the buffer reused. - */ - - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), size); + flush_kernel_dcache_range((unsigned long)phys_to_virt(paddr), size); } -static int pa11_dma_map_sg(struct device *dev, struct scatterlist *sglist, - int nents, enum dma_data_direction direction, - unsigned long attrs) -{ - int i; - struct scatterlist *sg; - - BUG_ON(direction == DMA_NONE); - - for_each_sg(sglist, sg, nents, i) { - unsigned long vaddr = (unsigned long)sg_virt(sg); - - sg_dma_address(sg) = (dma_addr_t) virt_to_phys(vaddr); - sg_dma_len(sg) = sg->length; - - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - continue; - - flush_kernel_dcache_range(vaddr, sg->length); - } - return nents; -} - -static void pa11_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, - int nents, enum dma_data_direction direction, - unsigned long attrs) -{ - int i; - struct scatterlist *sg; - - BUG_ON(direction == DMA_NONE); - - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - return; - - if (direction == DMA_TO_DEVICE) - return; - - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ - - for_each_sg(sglist, sg, nents, i) - flush_kernel_dcache_range(sg_virt(sg), sg->length); -} - -static void pa11_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), - size); -} - -static void pa11_dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - BUG_ON(direction == DMA_NONE); - - flush_kernel_dcache_range((unsigned long) phys_to_virt(dma_handle), - size); -} - -static void pa11_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) -{ - int i; - struct scatterlist *sg; - - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ - - for_each_sg(sglist, sg, nents, i) - flush_kernel_dcache_range(sg_virt(sg), sg->length); -} - -static void pa11_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sglist, int nents, enum dma_data_direction direction) -{ - int i; - struct scatterlist *sg; - - /* once we do combining we'll need to use phys_to_virt(sg_dma_address(sglist)) */ - - for_each_sg(sglist, sg, nents, i) - flush_kernel_dcache_range(sg_virt(sg), sg->length); -} - -static void pa11_dma_cache_sync(struct device *dev, void *vaddr, size_t size, +void arch_dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { flush_kernel_dcache_range((unsigned long)vaddr, size); } - -const struct dma_map_ops pa11_dma_ops = { - .alloc = pa11_dma_alloc, - .free = pa11_dma_free, - .map_page = pa11_dma_map_page, - .unmap_page = pa11_dma_unmap_page, - .map_sg = pa11_dma_map_sg, - .unmap_sg = pa11_dma_unmap_sg, - .sync_single_for_cpu = pa11_dma_sync_single_for_cpu, - .sync_single_for_device = pa11_dma_sync_single_for_device, - .sync_sg_for_cpu = pa11_dma_sync_sg_for_cpu, - .sync_sg_for_device = pa11_dma_sync_sg_for_device, - .cache_sync = pa11_dma_cache_sync, -}; diff --git a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c index 5c8450a22255..4e87c35c22b7 100644 --- a/arch/parisc/kernel/setup.c +++ b/arch/parisc/kernel/setup.c @@ -102,7 +102,7 @@ void __init dma_ops_init(void) case pcxl: /* falls through */ case pcxs: case pcxt: - hppa_dma_ops = &pa11_dma_ops; + hppa_dma_ops = &dma_noncoherent_ops; break; default: break; From 93cb8e20d56be40c541475f77b5f565fbb385a4b Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 1 Jul 2018 18:18:15 +0200 Subject: [PATCH 4/9] parisc: Drop architecture-specific ENOTSUP define parisc is the only Linux architecture which has defined a value for ENOTSUP. All other architectures #define ENOTSUP as EOPNOTSUPP in their libc headers. Having an own value for ENOTSUP which is different than EOPNOTSUPP often gives problems with userspace programs which expect both to be the same. One such example is a build error in the libuv package, as can be seen in https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=900237. Since we dropped HP-UX support, there is no real benefit in keeping an own value for ENOTSUP. This patch drops the parisc value for ENOTSUP from the kernel sources. glibc needs no patch, it reuses the exported headers. Signed-off-by: Helge Deller --- arch/parisc/include/uapi/asm/errno.h | 1 - kernel/time/posix-timers.c | 13 ++----------- tools/arch/parisc/include/uapi/asm/errno.h | 1 - 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/arch/parisc/include/uapi/asm/errno.h b/arch/parisc/include/uapi/asm/errno.h index fc0df353ff0d..87245c584784 100644 --- a/arch/parisc/include/uapi/asm/errno.h +++ b/arch/parisc/include/uapi/asm/errno.h @@ -113,7 +113,6 @@ #define ELOOP 249 /* Too many symbolic links encountered */ #define ENOSYS 251 /* Function not implemented */ -#define ENOTSUP 252 /* Function not implemented (POSIX.4 / HPUX) */ #define ECANCELLED 253 /* aio request was canceled before complete (POSIX.4 / HPUX) */ #define ECANCELED ECANCELLED /* SuSv3 and Solaris wants one 'L' */ diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c index e08ce3f27447..66321cbdf90c 100644 --- a/kernel/time/posix-timers.c +++ b/kernel/time/posix-timers.c @@ -85,15 +85,6 @@ static const struct k_clock clock_realtime, clock_monotonic; #error "SIGEV_THREAD_ID must not share bit with other SIGEV values!" #endif -/* - * parisc wants ENOTSUP instead of EOPNOTSUPP - */ -#ifndef ENOTSUP -# define ENANOSLEEP_NOTSUP EOPNOTSUPP -#else -# define ENANOSLEEP_NOTSUP ENOTSUP -#endif - /* * The timer ID is turned into a timer address by idr_find(). * Verifying a valid ID consists of: @@ -1220,7 +1211,7 @@ SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, if (!kc) return -EINVAL; if (!kc->nsleep) - return -ENANOSLEEP_NOTSUP; + return -EOPNOTSUPP; if (get_timespec64(&t, rqtp)) return -EFAULT; @@ -1247,7 +1238,7 @@ COMPAT_SYSCALL_DEFINE4(clock_nanosleep, clockid_t, which_clock, int, flags, if (!kc) return -EINVAL; if (!kc->nsleep) - return -ENANOSLEEP_NOTSUP; + return -EOPNOTSUPP; if (compat_get_timespec64(&t, rqtp)) return -EFAULT; diff --git a/tools/arch/parisc/include/uapi/asm/errno.h b/tools/arch/parisc/include/uapi/asm/errno.h index fc0df353ff0d..87245c584784 100644 --- a/tools/arch/parisc/include/uapi/asm/errno.h +++ b/tools/arch/parisc/include/uapi/asm/errno.h @@ -113,7 +113,6 @@ #define ELOOP 249 /* Too many symbolic links encountered */ #define ENOSYS 251 /* Function not implemented */ -#define ENOTSUP 252 /* Function not implemented (POSIX.4 / HPUX) */ #define ECANCELLED 253 /* aio request was canceled before complete (POSIX.4 / HPUX) */ #define ECANCELED ECANCELLED /* SuSv3 and Solaris wants one 'L' */ From 75ebedf1d26376cafad87b43196c15161463b82a Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 28 Jun 2018 22:47:11 +0200 Subject: [PATCH 5/9] parisc: Add HAVE_REGS_AND_STACK_ACCESS_API feature Some parts of the HAVE_REGS_AND_STACK_ACCESS_API feature is needed for the rseq syscall. This patch adds the most important parts, and as long as we don't support kprobes, we should be fine. Signed-off-by: Helge Deller --- arch/parisc/Kconfig | 1 + arch/parisc/include/asm/ptrace.h | 11 ++++ arch/parisc/kernel/ptrace.c | 100 +++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 1fcdf1565b23..e21751fb24aa 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig @@ -45,6 +45,7 @@ config PARISC select HAVE_ARCH_HASH select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK + select HAVE_REGS_AND_STACK_ACCESS_API select GENERIC_SCHED_CLOCK select HAVE_UNSTABLE_SCHED_CLOCK if SMP select GENERIC_CLOCKEVENTS diff --git a/arch/parisc/include/asm/ptrace.h b/arch/parisc/include/asm/ptrace.h index 46da07670c2b..2a27b275ab09 100644 --- a/arch/parisc/include/asm/ptrace.h +++ b/arch/parisc/include/asm/ptrace.h @@ -25,4 +25,15 @@ static inline unsigned long regs_return_value(struct pt_regs *regs) return regs->gr[20]; } +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + regs->iaoq[0] = val; +} + +/* Query offset/name of register from its name/offset */ +extern int regs_query_register_offset(const char *name); +extern const char *regs_query_register_name(unsigned int offset); +#define MAX_REG_OFFSET (offsetof(struct pt_regs, ipsw)) + #endif diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index 7aa1d4d0d444..2582df1c529b 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -676,3 +676,103 @@ const struct user_regset_view *task_user_regset_view(struct task_struct *task) #endif return &user_parisc_native_view; } + + +/* HAVE_REGS_AND_STACK_ACCESS_API feature */ + +struct pt_regs_offset { + const char *name; + int offset; +}; + +#define REG_OFFSET_NAME(r) {.name = #r, .offset = offsetof(struct pt_regs, r)} +#define REG_OFFSET_INDEX(r,i) {.name = #r#i, .offset = offsetof(struct pt_regs, r[i])} +#define REG_OFFSET_END {.name = NULL, .offset = 0} + +static const struct pt_regs_offset regoffset_table[] = { + REG_OFFSET_INDEX(gr,0), + REG_OFFSET_INDEX(gr,1), + REG_OFFSET_INDEX(gr,2), + REG_OFFSET_INDEX(gr,3), + REG_OFFSET_INDEX(gr,4), + REG_OFFSET_INDEX(gr,5), + REG_OFFSET_INDEX(gr,6), + REG_OFFSET_INDEX(gr,7), + REG_OFFSET_INDEX(gr,8), + REG_OFFSET_INDEX(gr,9), + REG_OFFSET_INDEX(gr,10), + REG_OFFSET_INDEX(gr,11), + REG_OFFSET_INDEX(gr,12), + REG_OFFSET_INDEX(gr,13), + REG_OFFSET_INDEX(gr,14), + REG_OFFSET_INDEX(gr,15), + REG_OFFSET_INDEX(gr,16), + REG_OFFSET_INDEX(gr,17), + REG_OFFSET_INDEX(gr,18), + REG_OFFSET_INDEX(gr,19), + REG_OFFSET_INDEX(gr,20), + REG_OFFSET_INDEX(gr,21), + REG_OFFSET_INDEX(gr,22), + REG_OFFSET_INDEX(gr,23), + REG_OFFSET_INDEX(gr,24), + REG_OFFSET_INDEX(gr,25), + REG_OFFSET_INDEX(gr,26), + REG_OFFSET_INDEX(gr,27), + REG_OFFSET_INDEX(gr,28), + REG_OFFSET_INDEX(gr,29), + REG_OFFSET_INDEX(gr,30), + REG_OFFSET_INDEX(gr,31), + REG_OFFSET_INDEX(sr,0), + REG_OFFSET_INDEX(sr,1), + REG_OFFSET_INDEX(sr,2), + REG_OFFSET_INDEX(sr,3), + REG_OFFSET_INDEX(sr,4), + REG_OFFSET_INDEX(sr,5), + REG_OFFSET_INDEX(sr,6), + REG_OFFSET_INDEX(sr,7), + REG_OFFSET_INDEX(iasq,0), + REG_OFFSET_INDEX(iasq,1), + REG_OFFSET_INDEX(iaoq,0), + REG_OFFSET_INDEX(iaoq,1), + REG_OFFSET_NAME(cr27), + REG_OFFSET_NAME(ksp), + REG_OFFSET_NAME(kpc), + REG_OFFSET_NAME(sar), + REG_OFFSET_NAME(iir), + REG_OFFSET_NAME(isr), + REG_OFFSET_NAME(ior), + REG_OFFSET_NAME(ipsw), + REG_OFFSET_END, +}; + +/** + * regs_query_register_offset() - query register offset from its name + * @name: the name of a register + * + * regs_query_register_offset() returns the offset of a register in struct + * pt_regs from its name. If the name is invalid, this returns -EINVAL; + */ +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_offset *roff; + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + return -EINVAL; +} + +/** + * regs_query_register_name() - query register name from its offset + * @offset: the offset of a register in struct pt_regs. + * + * regs_query_register_name() returns the name of a register from its + * offset in struct pt_regs. If the @offset is invalid, this returns NULL; + */ +const char *regs_query_register_name(unsigned int offset) +{ + const struct pt_regs_offset *roff; + for (roff = regoffset_table; roff->name != NULL; roff++) + if (roff->offset == offset) + return roff->name; + return NULL; +} From 4a53ec1ccf932f86845c96a5092ba4507621c84d Mon Sep 17 00:00:00 2001 From: Nick Desaulniers Date: Wed, 1 Aug 2018 11:22:56 -0700 Subject: [PATCH 6/9] parisc: prefer _THIS_IP_ and _RET_IP_ statement expressions As part of the effort to reduce the code duplication between _THIS_IP_ and current_text_addr(), let's consolidate callers of current_text_addr() to use _THIS_IP_. Signed-off-by: Nick Desaulniers Signed-off-by: Helge Deller --- arch/parisc/kernel/unwind.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index 2ef83d78eec4..a4b430f440a9 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -439,8 +439,8 @@ unsigned long return_address(unsigned int level) /* initialize unwind info */ asm volatile ("copy %%r30, %0" : "=r"(sp)); memset(&r, 0, sizeof(struct pt_regs)); - r.iaoq[0] = (unsigned long) current_text_addr(); - r.gr[2] = (unsigned long) __builtin_return_address(0); + r.iaoq[0] = _THIS_IP_; + r.gr[2] = _RET_IP_; r.gr[30] = sp; unwind_frame_init(&info, current, &r); From 7797167ffde1f00446301cb22b37b7c03194cfaf Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 12 Aug 2018 16:38:03 -0400 Subject: [PATCH 7/9] parisc: Remove ordered stores from syscall.S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that we use a sync prior to releasing the locks in syscall.S, we don't need the PA 2.0 ordered stores used to release some locks.  Using an ordered store, potentially slows the release and subsequent code. There are a number of other ordered stores and loads that serve no purpose.  I have converted these to normal stores. Signed-off-by: John David Anglin Cc: stable@vger.kernel.org # 4.0+ Signed-off-by: Helge Deller --- arch/parisc/kernel/syscall.S | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 4886a6db42e9..5f7e57fcaeef 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -629,12 +629,12 @@ cas_action: stw %r1, 4(%sr2,%r20) #endif /* The load and store could fail */ -1: ldw,ma 0(%r26), %r28 +1: ldw 0(%r26), %r28 sub,<> %r28, %r25, %r0 -2: stw,ma %r24, 0(%r26) +2: stw %r24, 0(%r26) /* Free lock */ sync - stw,ma %r20, 0(%sr2,%r20) + stw %r20, 0(%sr2,%r20) #if ENABLE_LWS_DEBUG /* Clear thread register indicator */ stw %r0, 4(%sr2,%r20) @@ -798,30 +798,30 @@ cas2_action: ldo 1(%r0),%r28 /* 8bit CAS */ -13: ldb,ma 0(%r26), %r29 +13: ldb 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -14: stb,ma %r24, 0(%r26) +14: stb %r24, 0(%r26) b cas2_end copy %r0, %r28 nop nop /* 16bit CAS */ -15: ldh,ma 0(%r26), %r29 +15: ldh 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -16: sth,ma %r24, 0(%r26) +16: sth %r24, 0(%r26) b cas2_end copy %r0, %r28 nop nop /* 32bit CAS */ -17: ldw,ma 0(%r26), %r29 +17: ldw 0(%r26), %r29 sub,= %r29, %r25, %r0 b,n cas2_end -18: stw,ma %r24, 0(%r26) +18: stw %r24, 0(%r26) b cas2_end copy %r0, %r28 nop @@ -829,10 +829,10 @@ cas2_action: /* 64bit CAS */ #ifdef CONFIG_64BIT -19: ldd,ma 0(%r26), %r29 +19: ldd 0(%r26), %r29 sub,*= %r29, %r25, %r0 b,n cas2_end -20: std,ma %r24, 0(%r26) +20: std %r24, 0(%r26) copy %r0, %r28 #else /* Compare first word */ @@ -851,7 +851,7 @@ cas2_action: cas2_end: /* Free lock */ sync - stw,ma %r20, 0(%sr2,%r20) + stw %r20, 0(%sr2,%r20) /* Enable interrupts */ ssm PSW_SM_I, %r0 /* Return to userspace, set no error */ From 3b885ac1dc35b87a39ee176a6c7e2af9c789d8b8 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Sun, 12 Aug 2018 16:31:17 -0400 Subject: [PATCH 8/9] parisc: Remove unnecessary barriers from spinlock.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that mb() is an instruction barrier, it will slow performance if we issue unnecessary barriers. The spinlock defines have a number of unnecessary barriers.  The __ldcw() define is both a hardware and compiler barrier.  The mb() barriers in the routines using __ldcw() serve no purpose. The only barrier needed is the one in arch_spin_unlock().  We need to ensure all accesses are complete prior to releasing the lock. Signed-off-by: John David Anglin Cc: stable@vger.kernel.org # 4.0+ Signed-off-by: Helge Deller --- arch/parisc/include/asm/spinlock.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/parisc/include/asm/spinlock.h b/arch/parisc/include/asm/spinlock.h index 6f84b6acc86e..8a63515f03bf 100644 --- a/arch/parisc/include/asm/spinlock.h +++ b/arch/parisc/include/asm/spinlock.h @@ -20,7 +20,6 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *x, { volatile unsigned int *a; - mb(); a = __ldcw_align(x); while (__ldcw(a) == 0) while (*a == 0) @@ -30,17 +29,16 @@ static inline void arch_spin_lock_flags(arch_spinlock_t *x, local_irq_disable(); } else cpu_relax(); - mb(); } #define arch_spin_lock_flags arch_spin_lock_flags static inline void arch_spin_unlock(arch_spinlock_t *x) { volatile unsigned int *a; - mb(); + a = __ldcw_align(x); - *a = 1; mb(); + *a = 1; } static inline int arch_spin_trylock(arch_spinlock_t *x) @@ -48,10 +46,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *x) volatile unsigned int *a; int ret; - mb(); a = __ldcw_align(x); ret = __ldcw(a) != 0; - mb(); return ret; } From c8921d72e390cb6fca3fb2b0c2badfda851647eb Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Sun, 5 Aug 2018 00:03:29 +0200 Subject: [PATCH 9/9] parisc: Fix and improve kernel stack unwinding This patchset fixes and improves stack unwinding a lot: 1. Show backward stack traces with up to 30 callsites 2. Add callinfo to ENTRY_CFI() such that every assembler function will get an entry in the unwind table 3. Use constants instead of numbers in call_on_stack() 4. Do not depend on CONFIG_KALLSYMS to generate backtraces. 5. Speed up backtrace generation Make sure you have this patch to GNU as installed: https://sourceware.org/ml/binutils/2018-07/msg00474.html Without this patch, unwind info in the kernel is often wrong for various functions. Signed-off-by: Helge Deller --- arch/parisc/include/asm/assembly.h | 2 + arch/parisc/include/asm/linkage.h | 17 ++-- arch/parisc/include/asm/unwind.h | 3 + arch/parisc/kernel/entry.S | 53 +++++------- arch/parisc/kernel/pacache.S | 125 ----------------------------- arch/parisc/kernel/process.c | 2 +- arch/parisc/kernel/real2.S | 6 -- arch/parisc/kernel/traps.c | 2 +- arch/parisc/kernel/unwind.c | 89 +++++++++++--------- arch/parisc/lib/lusercopy.S | 21 ----- 10 files changed, 88 insertions(+), 232 deletions(-) diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h index 60e6f07b7e32..e9c6385ef0d1 100644 --- a/arch/parisc/include/asm/assembly.h +++ b/arch/parisc/include/asm/assembly.h @@ -36,6 +36,7 @@ #define RP_OFFSET 16 #define FRAME_SIZE 128 #define CALLEE_REG_FRAME_SIZE 144 +#define REG_SZ 8 #define ASM_ULONG_INSN .dword #else /* CONFIG_64BIT */ #define LDREG ldw @@ -50,6 +51,7 @@ #define RP_OFFSET 20 #define FRAME_SIZE 64 #define CALLEE_REG_FRAME_SIZE 128 +#define REG_SZ 4 #define ASM_ULONG_INSN .word #endif diff --git a/arch/parisc/include/asm/linkage.h b/arch/parisc/include/asm/linkage.h index 9a69bf6fc4b6..49f6f3d772cc 100644 --- a/arch/parisc/include/asm/linkage.h +++ b/arch/parisc/include/asm/linkage.h @@ -18,9 +18,9 @@ #ifdef __ASSEMBLY__ #define ENTRY(name) \ - .export name !\ - ALIGN !\ -name: + ALIGN !\ +name: ASM_NL\ + .export name #ifdef CONFIG_64BIT #define ENDPROC(name) \ @@ -31,13 +31,18 @@ END(name) #endif -#define ENTRY_CFI(name) \ +#define ENTRY_CFI(name, ...) \ ENTRY(name) ASM_NL\ + .proc ASM_NL\ + .callinfo __VA_ARGS__ ASM_NL\ + .entry ASM_NL\ CFI_STARTPROC #define ENDPROC_CFI(name) \ - ENDPROC(name) ASM_NL\ - CFI_ENDPROC + CFI_ENDPROC ASM_NL\ + .exit ASM_NL\ + .procend ASM_NL\ + ENDPROC(name) #endif /* __ASSEMBLY__ */ diff --git a/arch/parisc/include/asm/unwind.h b/arch/parisc/include/asm/unwind.h index c73a3ee20226..f133b7efbebb 100644 --- a/arch/parisc/include/asm/unwind.h +++ b/arch/parisc/include/asm/unwind.h @@ -4,6 +4,9 @@ #include +/* Max number of levels to backtrace */ +#define MAX_UNWIND_ENTRIES 30 + /* From ABI specifications */ struct unwind_table_entry { unsigned int region_start; diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 1b4732e20137..c7508f5717fb 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S @@ -766,7 +766,6 @@ END(fault_vector_11) #endif /* Fault vector is separately protected and *must* be on its own page */ .align PAGE_SIZE -ENTRY(end_fault_vector) .import handle_interruption,code .import do_cpu_irq_mask,code @@ -778,7 +777,6 @@ ENTRY(end_fault_vector) */ ENTRY_CFI(ret_from_kernel_thread) - /* Call schedule_tail first though */ BL schedule_tail, %r2 nop @@ -817,8 +815,9 @@ ENTRY_CFI(_switch_to) LDREG TASK_THREAD_INFO(%r25), %r25 bv %r0(%r2) mtctl %r25,%cr30 +ENDPROC_CFI(_switch_to) -_switch_to_ret: +ENTRY_CFI(_switch_to_ret) mtctl %r0, %cr0 /* Needed for single stepping */ callee_rest callee_rest_float @@ -826,7 +825,7 @@ _switch_to_ret: LDREG -RP_OFFSET(%r30), %r2 bv %r0(%r2) copy %r26, %r28 -ENDPROC_CFI(_switch_to) +ENDPROC_CFI(_switch_to_ret) /* * Common rfi return path for interruptions, kernel execve, and @@ -887,12 +886,14 @@ ENTRY_CFI(syscall_exit_rfi) STREG %r19,PT_SR5(%r16) STREG %r19,PT_SR6(%r16) STREG %r19,PT_SR7(%r16) +ENDPROC_CFI(syscall_exit_rfi) -intr_return: +ENTRY_CFI(intr_return) /* check for reschedule */ mfctl %cr30,%r1 LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ bb,<,n %r19,31-TIF_NEED_RESCHED,intr_do_resched /* forward */ +ENDPROC_CFI(intr_return) .import do_notify_resume,code intr_check_sig: @@ -1048,7 +1049,6 @@ intr_extint: b do_cpu_irq_mask ldo R%intr_return(%r2), %r2 /* return to intr_return, not here */ -ENDPROC_CFI(syscall_exit_rfi) /* Generic interruptions (illegal insn, unaligned, page fault, etc) */ @@ -1999,12 +1999,9 @@ ENDPROC_CFI(syscall_exit) .align L1_CACHE_BYTES .globl mcount .type mcount, @function -ENTRY(mcount) +ENTRY_CFI(mcount, caller) _mcount: .export _mcount,data - .proc - .callinfo caller,frame=0 - .entry /* * The 64bit mcount() function pointer needs 4 dwords, of which the * first two are free. We optimize it here and put 2 instructions for @@ -2026,18 +2023,13 @@ ftrace_stub: .dword mcount .dword 0 /* code in head.S puts value of global gp here */ #endif - .exit - .procend -ENDPROC(mcount) +ENDPROC_CFI(mcount) #ifdef CONFIG_FUNCTION_GRAPH_TRACER .align 8 .globl return_to_handler .type return_to_handler, @function -ENTRY_CFI(return_to_handler) - .proc - .callinfo caller,frame=FRAME_SIZE - .entry +ENTRY_CFI(return_to_handler, caller,frame=FRAME_SIZE) .export parisc_return_to_handler,data parisc_return_to_handler: copy %r3,%r1 @@ -2076,8 +2068,6 @@ parisc_return_to_handler: bv %r0(%rp) #endif LDREGM -FRAME_SIZE(%sp),%r3 - .exit - .procend ENDPROC_CFI(return_to_handler) #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ @@ -2087,31 +2077,30 @@ ENDPROC_CFI(return_to_handler) #ifdef CONFIG_IRQSTACKS /* void call_on_stack(unsigned long param1, void *func, unsigned long new_stack) */ -ENTRY_CFI(call_on_stack) +ENTRY_CFI(call_on_stack, FRAME=2*FRAME_SIZE,CALLS,SAVE_RP,SAVE_SP) copy %sp, %r1 /* Regarding the HPPA calling conventions for function pointers, we assume the PIC register is not changed across call. For CONFIG_64BIT, the argument pointer is left to point at the argument region allocated for the call to call_on_stack. */ + + /* Switch to new stack. We allocate two frames. */ + ldo 2*FRAME_SIZE(%arg2), %sp # ifdef CONFIG_64BIT - /* Switch to new stack. We allocate two 128 byte frames. */ - ldo 256(%arg2), %sp /* Save previous stack pointer and return pointer in frame marker */ - STREG %rp, -144(%sp) + STREG %rp, -FRAME_SIZE-RP_OFFSET(%sp) /* Calls always use function descriptor */ LDREG 16(%arg1), %arg1 bve,l (%arg1), %rp - STREG %r1, -136(%sp) - LDREG -144(%sp), %rp + STREG %r1, -FRAME_SIZE-REG_SZ(%sp) + LDREG -FRAME_SIZE-RP_OFFSET(%sp), %rp bve (%rp) - LDREG -136(%sp), %sp + LDREG -FRAME_SIZE-REG_SZ(%sp), %sp # else - /* Switch to new stack. We allocate two 64 byte frames. */ - ldo 128(%arg2), %sp /* Save previous stack pointer and return pointer in frame marker */ - STREG %r1, -68(%sp) - STREG %rp, -84(%sp) + STREG %r1, -FRAME_SIZE-REG_SZ(%sp) + STREG %rp, -FRAME_SIZE-RP_OFFSET(%sp) /* Calls use function descriptor if PLABEL bit is set */ bb,>=,n %arg1, 30, 1f depwi 0,31,2, %arg1 @@ -2119,9 +2108,9 @@ ENTRY_CFI(call_on_stack) 1: be,l 0(%sr4,%arg1), %sr0, %r31 copy %r31, %rp - LDREG -84(%sp), %rp + LDREG -FRAME_SIZE-RP_OFFSET(%sp), %rp bv (%rp) - LDREG -68(%sp), %sp + LDREG -FRAME_SIZE-REG_SZ(%sp), %sp # endif /* CONFIG_64BIT */ ENDPROC_CFI(call_on_stack) #endif /* CONFIG_IRQSTACKS */ diff --git a/arch/parisc/kernel/pacache.S b/arch/parisc/kernel/pacache.S index 97451e67d35b..f33bf2d306d6 100644 --- a/arch/parisc/kernel/pacache.S +++ b/arch/parisc/kernel/pacache.S @@ -44,10 +44,6 @@ .align 16 ENTRY_CFI(flush_tlb_all_local) - .proc - .callinfo NO_CALLS - .entry - /* * The pitlbe and pdtlbe instructions should only be used to * flush the entire tlb. Also, there needs to be no intervening @@ -189,18 +185,11 @@ fdtdone: 2: bv %r0(%r2) nop - - .exit - .procend ENDPROC_CFI(flush_tlb_all_local) .import cache_info,data ENTRY_CFI(flush_instruction_cache_local) - .proc - .callinfo NO_CALLS - .entry - load32 cache_info, %r1 /* Flush Instruction Cache */ @@ -256,18 +245,11 @@ fisync: mtsm %r22 /* restore I-bit */ bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_instruction_cache_local) .import cache_info, data ENTRY_CFI(flush_data_cache_local) - .proc - .callinfo NO_CALLS - .entry - load32 cache_info, %r1 /* Flush Data Cache */ @@ -324,9 +306,6 @@ fdsync: mtsm %r22 /* restore I-bit */ bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_data_cache_local) /* Macros to serialize TLB purge operations on SMP. */ @@ -362,10 +341,6 @@ ENDPROC_CFI(flush_data_cache_local) /* Clear page using kernel mapping. */ ENTRY_CFI(clear_page_asm) - .proc - .callinfo NO_CALLS - .entry - #ifdef CONFIG_64BIT /* Unroll the loop. */ @@ -424,18 +399,11 @@ ENTRY_CFI(clear_page_asm) #endif bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(clear_page_asm) /* Copy page using kernel mapping. */ ENTRY_CFI(copy_page_asm) - .proc - .callinfo NO_CALLS - .entry - #ifdef CONFIG_64BIT /* PA8x00 CPUs can consume 2 loads or 1 store per cycle. * Unroll the loop by hand and arrange insn appropriately. @@ -542,9 +510,6 @@ ENTRY_CFI(copy_page_asm) #endif bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(copy_page_asm) /* @@ -598,10 +563,6 @@ ENDPROC_CFI(copy_page_asm) */ ENTRY_CFI(copy_user_page_asm) - .proc - .callinfo NO_CALLS - .entry - /* Convert virtual `to' and `from' addresses to physical addresses. Move `from' physical address to non shadowed register. */ ldil L%(__PAGE_OFFSET), %r1 @@ -750,16 +711,9 @@ ENTRY_CFI(copy_user_page_asm) bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(copy_user_page_asm) ENTRY_CFI(clear_user_page_asm) - .proc - .callinfo NO_CALLS - .entry - tophys_r1 %r26 ldil L%(TMPALIAS_MAP_START), %r28 @@ -836,16 +790,9 @@ ENTRY_CFI(clear_user_page_asm) bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(clear_user_page_asm) ENTRY_CFI(flush_dcache_page_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%(TMPALIAS_MAP_START), %r28 #ifdef CONFIG_64BIT #if (TMPALIAS_MAP_START >= 0x80000000) @@ -903,16 +850,9 @@ ENTRY_CFI(flush_dcache_page_asm) sync bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_dcache_page_asm) ENTRY_CFI(flush_icache_page_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%(TMPALIAS_MAP_START), %r28 #ifdef CONFIG_64BIT #if (TMPALIAS_MAP_START >= 0x80000000) @@ -977,16 +917,9 @@ ENTRY_CFI(flush_icache_page_asm) sync bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_icache_page_asm) ENTRY_CFI(flush_kernel_dcache_page_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 @@ -1020,16 +953,9 @@ ENTRY_CFI(flush_kernel_dcache_page_asm) sync bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_kernel_dcache_page_asm) ENTRY_CFI(purge_kernel_dcache_page_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 @@ -1062,16 +988,9 @@ ENTRY_CFI(purge_kernel_dcache_page_asm) sync bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(purge_kernel_dcache_page_asm) ENTRY_CFI(flush_user_dcache_range_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 ldo -1(%r23), %r21 @@ -1083,16 +1002,9 @@ ENTRY_CFI(flush_user_dcache_range_asm) sync bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_user_dcache_range_asm) ENTRY_CFI(flush_kernel_dcache_range_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 ldo -1(%r23), %r21 @@ -1105,16 +1017,9 @@ ENTRY_CFI(flush_kernel_dcache_range_asm) syncdma bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_kernel_dcache_range_asm) ENTRY_CFI(purge_kernel_dcache_range_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%dcache_stride, %r1 ldw R%dcache_stride(%r1), %r23 ldo -1(%r23), %r21 @@ -1127,16 +1032,9 @@ ENTRY_CFI(purge_kernel_dcache_range_asm) syncdma bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(purge_kernel_dcache_range_asm) ENTRY_CFI(flush_user_icache_range_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r23 ldo -1(%r23), %r21 @@ -1148,16 +1046,9 @@ ENTRY_CFI(flush_user_icache_range_asm) sync bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_user_icache_range_asm) ENTRY_CFI(flush_kernel_icache_page) - .proc - .callinfo NO_CALLS - .entry - ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r23 @@ -1191,16 +1082,9 @@ ENTRY_CFI(flush_kernel_icache_page) sync bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(flush_kernel_icache_page) ENTRY_CFI(flush_kernel_icache_range_asm) - .proc - .callinfo NO_CALLS - .entry - ldil L%icache_stride, %r1 ldw R%icache_stride(%r1), %r23 ldo -1(%r23), %r21 @@ -1212,8 +1096,6 @@ ENTRY_CFI(flush_kernel_icache_range_asm) sync bv %r0(%r2) nop - .exit - .procend ENDPROC_CFI(flush_kernel_icache_range_asm) __INIT @@ -1223,10 +1105,6 @@ ENDPROC_CFI(flush_kernel_icache_range_asm) */ .align 256 ENTRY_CFI(disable_sr_hashing_asm) - .proc - .callinfo NO_CALLS - .entry - /* * Switch to real mode */ @@ -1308,9 +1186,6 @@ srdis_done: 2: bv %r0(%r2) nop - .exit - - .procend ENDPROC_CFI(disable_sr_hashing_asm) .end diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index b931745815e0..eb39e7e380d7 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -302,7 +302,7 @@ get_wchan(struct task_struct *p) ip = info.ip; if (!in_sched_functions(ip)) return ip; - } while (count++ < 16); + } while (count++ < MAX_UNWIND_ENTRIES); return 0; } diff --git a/arch/parisc/kernel/real2.S b/arch/parisc/kernel/real2.S index cc9963421a19..2b16d8d6598f 100644 --- a/arch/parisc/kernel/real2.S +++ b/arch/parisc/kernel/real2.S @@ -35,12 +35,6 @@ real32_stack: real64_stack: .block 8192 -#ifdef CONFIG_64BIT -# define REG_SZ 8 -#else -# define REG_SZ 4 -#endif - #define N_SAVED_REGS 9 save_cr_space: diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 4309ad31a874..318815212518 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -172,7 +172,7 @@ static void do_show_stack(struct unwind_frame_info *info) int i = 1; printk(KERN_CRIT "Backtrace:\n"); - while (i <= 16) { + while (i <= MAX_UNWIND_ENTRIES) { if (unwind_once(info) < 0 || info->ip == 0) break; diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index a4b430f440a9..5cdf13069dd9 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -117,7 +116,8 @@ unwind_table_init(struct unwind_table *table, const char *name, for (; start <= end; start++) { if (start < end && start->region_end > (start+1)->region_start) { - printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1); + pr_warn("Out of order unwind entry! %px and %px\n", + start, start+1); } start->region_start += base_addr; @@ -203,26 +203,61 @@ int __init unwind_init(void) return 0; } -#ifdef CONFIG_64BIT -#define get_func_addr(fptr) fptr[2] -#else -#define get_func_addr(fptr) fptr[0] -#endif - static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size) { - extern void handle_interruption(int, struct pt_regs *); - static unsigned long *hi = (unsigned long *)&handle_interruption; + /* + * We have to use void * instead of a function pointer, because + * function pointers aren't a pointer to the function on 64-bit. + * Make them const so the compiler knows they live in .text + */ + extern void * const handle_interruption; + extern void * const ret_from_kernel_thread; + extern void * const syscall_exit; + extern void * const intr_return; + extern void * const _switch_to_ret; +#ifdef CONFIG_IRQSTACKS + extern void * const call_on_stack; +#endif /* CONFIG_IRQSTACKS */ - if (pc == get_func_addr(hi)) { + if (pc == (unsigned long) &handle_interruption) { struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN); dbg("Unwinding through handle_interruption()\n"); info->prev_sp = regs->gr[30]; info->prev_ip = regs->iaoq[0]; - return 1; } + if (pc == (unsigned long) &ret_from_kernel_thread || + pc == (unsigned long) &syscall_exit) { + info->prev_sp = info->prev_ip = 0; + return 1; + } + + if (pc == (unsigned long) &intr_return) { + struct pt_regs *regs; + + dbg("Found intr_return()\n"); + regs = (struct pt_regs *)(info->sp - PT_SZ_ALGN); + info->prev_sp = regs->gr[30]; + info->prev_ip = regs->iaoq[0]; + info->rp = regs->gr[2]; + return 1; + } + + if (pc == (unsigned long) &_switch_to_ret) { + info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE; + info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET); + return 1; + } + +#ifdef CONFIG_IRQSTACKS + if (pc == (unsigned long) &call_on_stack) { + info->prev_sp = *(unsigned long *)(info->sp - FRAME_SIZE - REG_SZ); + info->prev_ip = *(unsigned long *)(info->sp - FRAME_SIZE - RP_OFFSET); + return 1; + } +#endif + return 0; } @@ -238,34 +273,8 @@ static void unwind_frame_regs(struct unwind_frame_info *info) if (e == NULL) { unsigned long sp; - dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip); - -#ifdef CONFIG_KALLSYMS - /* Handle some frequent special cases.... */ - { - char symname[KSYM_NAME_LEN]; - char *modname; - - kallsyms_lookup(info->ip, NULL, NULL, &modname, - symname); - - dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname); - - if (strcmp(symname, "_switch_to_ret") == 0) { - info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE; - info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET); - dbg("_switch_to_ret @ %lx - setting " - "prev_sp=%lx prev_ip=%lx\n", - info->ip, info->prev_sp, - info->prev_ip); - return; - } else if (strcmp(symname, "ret_from_kernel_thread") == 0 || - strcmp(symname, "syscall_exit") == 0) { - info->prev_ip = info->prev_sp = 0; - return; - } - } -#endif + dbg("Cannot find unwind entry for %pS; forced unwinding\n", + (void *) info->ip); /* Since we are doing the unwinding blind, we don't know if we are adjusting the stack correctly or extracting the rp diff --git a/arch/parisc/lib/lusercopy.S b/arch/parisc/lib/lusercopy.S index d4fe19806d57..b53fb6fedf06 100644 --- a/arch/parisc/lib/lusercopy.S +++ b/arch/parisc/lib/lusercopy.S @@ -64,9 +64,6 @@ */ ENTRY_CFI(lclear_user) - .proc - .callinfo NO_CALLS - .entry comib,=,n 0,%r25,$lclu_done get_sr $lclu_loop: @@ -81,13 +78,9 @@ $lclu_done: ldo 1(%r25),%r25 ASM_EXCEPTIONTABLE_ENTRY(1b,2b) - - .exit ENDPROC_CFI(lclear_user) - .procend - /* * long lstrnlen_user(char *s, long n) * @@ -97,9 +90,6 @@ ENDPROC_CFI(lclear_user) */ ENTRY_CFI(lstrnlen_user) - .proc - .callinfo NO_CALLS - .entry comib,= 0,%r25,$lslen_nzero copy %r26,%r24 get_sr @@ -111,7 +101,6 @@ $lslen_loop: $lslen_done: bv %r0(%r2) sub %r26,%r24,%r28 - .exit $lslen_nzero: b $lslen_done @@ -125,9 +114,6 @@ $lslen_nzero: ENDPROC_CFI(lstrnlen_user) - .procend - - /* * unsigned long pa_memcpy(void *dstp, const void *srcp, unsigned long len) @@ -186,10 +172,6 @@ ENDPROC_CFI(lstrnlen_user) save_len = r31 ENTRY_CFI(pa_memcpy) - .proc - .callinfo NO_CALLS - .entry - /* Last destination address */ add dst,len,end @@ -439,9 +421,6 @@ ENTRY_CFI(pa_memcpy) b .Lcopy_done 10: stw,ma t1,4(dstspc,dst) ASM_EXCEPTIONTABLE_ENTRY(10b,.Lcopy_done) - - .exit ENDPROC_CFI(pa_memcpy) - .procend .end