diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-21 13:47:13 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-21 13:47:13 -0500 |
commit | 0c961c5511fe48834c73215d2203bdac3353dcae (patch) | |
tree | a27fe6de2c087f4f72eb9e2f6ce7af8ea3cd6b51 | |
parent | bc1ecd626bedfa6b8cb09bacd56756ad18aed08f (diff) | |
parent | 160494d381373cfa21208484aea4e5db2d3cb0a8 (diff) |
Merge branch 'parisc-4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux
Pull parisc updates from Helge Deller:
- add Kernel address space layout randomization support
- re-enable interrupts earlier now that we have a working IRQ stack
- optimize the timer interrupt function to better cope with missed
timer irqs
- fix error return code in parisc perf code (by Dan Carpenter)
- fix PAT debug code
* 'parisc-4.10-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller/parisc-linux:
parisc: Optimize timer interrupt function
parisc: perf: return -EFAULT on error
parisc: Enhance CPU detection code on PAT machines
parisc: Re-enable interrupts early
parisc: Enable KASLR
-rw-r--r-- | arch/parisc/Kconfig | 1 | ||||
-rw-r--r-- | arch/parisc/include/asm/elf.h | 7 | ||||
-rw-r--r-- | arch/parisc/include/asm/pdcpat.h | 2 | ||||
-rw-r--r-- | arch/parisc/include/asm/processor.h | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/entry.S | 12 | ||||
-rw-r--r-- | arch/parisc/kernel/firmware.c | 2 | ||||
-rw-r--r-- | arch/parisc/kernel/inventory.c | 8 | ||||
-rw-r--r-- | arch/parisc/kernel/perf.c | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/process.c | 6 | ||||
-rw-r--r-- | arch/parisc/kernel/processor.c | 29 | ||||
-rw-r--r-- | arch/parisc/kernel/sys_parisc.c | 18 | ||||
-rw-r--r-- | arch/parisc/kernel/time.c | 112 |
12 files changed, 67 insertions, 139 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index a14b86587013..3a71f38cdc05 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -7,6 +7,7 @@ config PARISC | |||
7 | select HAVE_FUNCTION_GRAPH_TRACER | 7 | select HAVE_FUNCTION_GRAPH_TRACER |
8 | select HAVE_SYSCALL_TRACEPOINTS | 8 | select HAVE_SYSCALL_TRACEPOINTS |
9 | select ARCH_WANT_FRAME_POINTERS | 9 | select ARCH_WANT_FRAME_POINTERS |
10 | select ARCH_HAS_ELF_RANDOMIZE | ||
10 | select RTC_CLASS | 11 | select RTC_CLASS |
11 | select RTC_DRV_GENERIC | 12 | select RTC_DRV_GENERIC |
12 | select INIT_ALL_POSSIBLE | 13 | select INIT_ALL_POSSIBLE |
diff --git a/arch/parisc/include/asm/elf.h b/arch/parisc/include/asm/elf.h index 78c9fd32c554..a6b2a421571e 100644 --- a/arch/parisc/include/asm/elf.h +++ b/arch/parisc/include/asm/elf.h | |||
@@ -348,9 +348,10 @@ struct pt_regs; /* forward declaration... */ | |||
348 | 348 | ||
349 | #define ELF_HWCAP 0 | 349 | #define ELF_HWCAP 0 |
350 | 350 | ||
351 | #define STACK_RND_MASK (is_32bit_task() ? \ | 351 | /* Masks for stack and mmap randomization */ |
352 | 0x7ff >> (PAGE_SHIFT - 12) : \ | 352 | #define BRK_RND_MASK (is_32bit_task() ? 0x07ffUL : 0x3ffffUL) |
353 | 0x3ffff >> (PAGE_SHIFT - 12)) | 353 | #define MMAP_RND_MASK (is_32bit_task() ? 0x1fffUL : 0x3ffffUL) |
354 | #define STACK_RND_MASK MMAP_RND_MASK | ||
354 | 355 | ||
355 | struct mm_struct; | 356 | struct mm_struct; |
356 | extern unsigned long arch_randomize_brk(struct mm_struct *); | 357 | extern unsigned long arch_randomize_brk(struct mm_struct *); |
diff --git a/arch/parisc/include/asm/pdcpat.h b/arch/parisc/include/asm/pdcpat.h index 47539f117958..e1d289092705 100644 --- a/arch/parisc/include/asm/pdcpat.h +++ b/arch/parisc/include/asm/pdcpat.h | |||
@@ -289,7 +289,7 @@ extern int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info); | |||
289 | extern int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod, unsigned long view_type, void *mem_addr); | 289 | extern int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long mod, unsigned long view_type, void *mem_addr); |
290 | extern int pdc_pat_cell_num_to_loc(void *, unsigned long); | 290 | extern int pdc_pat_cell_num_to_loc(void *, unsigned long); |
291 | 291 | ||
292 | extern int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa); | 292 | extern int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, unsigned long hpa); |
293 | 293 | ||
294 | extern int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, unsigned long count, unsigned long offset); | 294 | extern int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr, unsigned long count, unsigned long offset); |
295 | 295 | ||
diff --git a/arch/parisc/include/asm/processor.h b/arch/parisc/include/asm/processor.h index ca40741378be..a3661ee6b060 100644 --- a/arch/parisc/include/asm/processor.h +++ b/arch/parisc/include/asm/processor.h | |||
@@ -93,9 +93,7 @@ struct system_cpuinfo_parisc { | |||
93 | /* Per CPU data structure - ie varies per CPU. */ | 93 | /* Per CPU data structure - ie varies per CPU. */ |
94 | struct cpuinfo_parisc { | 94 | struct cpuinfo_parisc { |
95 | unsigned long it_value; /* Interval Timer at last timer Intr */ | 95 | unsigned long it_value; /* Interval Timer at last timer Intr */ |
96 | unsigned long it_delta; /* Interval delta (tic_10ms / HZ * 100) */ | ||
97 | unsigned long irq_count; /* number of IRQ's since boot */ | 96 | unsigned long irq_count; /* number of IRQ's since boot */ |
98 | unsigned long irq_max_cr16; /* longest time to handle a single IRQ */ | ||
99 | unsigned long cpuid; /* aka slot_number or set to NO_PROC_ID */ | 97 | unsigned long cpuid; /* aka slot_number or set to NO_PROC_ID */ |
100 | unsigned long hpa; /* Host Physical address */ | 98 | unsigned long hpa; /* Host Physical address */ |
101 | unsigned long txn_addr; /* MMIO addr of EIR or id_eid */ | 99 | unsigned long txn_addr; /* MMIO addr of EIR or id_eid */ |
@@ -103,8 +101,6 @@ struct cpuinfo_parisc { | |||
103 | unsigned long pending_ipi; /* bitmap of type ipi_message_type */ | 101 | unsigned long pending_ipi; /* bitmap of type ipi_message_type */ |
104 | #endif | 102 | #endif |
105 | unsigned long bh_count; /* number of times bh was invoked */ | 103 | unsigned long bh_count; /* number of times bh was invoked */ |
106 | unsigned long prof_counter; /* per CPU profiling support */ | ||
107 | unsigned long prof_multiplier; /* per CPU profiling support */ | ||
108 | unsigned long fp_rev; | 104 | unsigned long fp_rev; |
109 | unsigned long fp_model; | 105 | unsigned long fp_model; |
110 | unsigned int state; | 106 | unsigned int state; |
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S index 4fcff2dcc9c3..ad4cb1613c57 100644 --- a/arch/parisc/kernel/entry.S +++ b/arch/parisc/kernel/entry.S | |||
@@ -878,6 +878,9 @@ ENTRY_CFI(syscall_exit_rfi) | |||
878 | STREG %r19,PT_SR7(%r16) | 878 | STREG %r19,PT_SR7(%r16) |
879 | 879 | ||
880 | intr_return: | 880 | intr_return: |
881 | /* NOTE: Need to enable interrupts incase we schedule. */ | ||
882 | ssm PSW_SM_I, %r0 | ||
883 | |||
881 | /* check for reschedule */ | 884 | /* check for reschedule */ |
882 | mfctl %cr30,%r1 | 885 | mfctl %cr30,%r1 |
883 | LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ | 886 | LDREG TI_FLAGS(%r1),%r19 /* sched.h: TIF_NEED_RESCHED */ |
@@ -904,11 +907,6 @@ intr_check_sig: | |||
904 | LDREG PT_IASQ1(%r16), %r20 | 907 | LDREG PT_IASQ1(%r16), %r20 |
905 | cmpib,COND(=),n 0,%r20,intr_restore /* backward */ | 908 | cmpib,COND(=),n 0,%r20,intr_restore /* backward */ |
906 | 909 | ||
907 | /* NOTE: We need to enable interrupts if we have to deliver | ||
908 | * signals. We used to do this earlier but it caused kernel | ||
909 | * stack overflows. */ | ||
910 | ssm PSW_SM_I, %r0 | ||
911 | |||
912 | copy %r0, %r25 /* long in_syscall = 0 */ | 910 | copy %r0, %r25 /* long in_syscall = 0 */ |
913 | #ifdef CONFIG_64BIT | 911 | #ifdef CONFIG_64BIT |
914 | ldo -16(%r30),%r29 /* Reference param save area */ | 912 | ldo -16(%r30),%r29 /* Reference param save area */ |
@@ -960,10 +958,6 @@ intr_do_resched: | |||
960 | cmpib,COND(=) 0, %r20, intr_do_preempt | 958 | cmpib,COND(=) 0, %r20, intr_do_preempt |
961 | nop | 959 | nop |
962 | 960 | ||
963 | /* NOTE: We need to enable interrupts if we schedule. We used | ||
964 | * to do this earlier but it caused kernel stack overflows. */ | ||
965 | ssm PSW_SM_I, %r0 | ||
966 | |||
967 | #ifdef CONFIG_64BIT | 961 | #ifdef CONFIG_64BIT |
968 | ldo -16(%r30),%r29 /* Reference param save area */ | 962 | ldo -16(%r30),%r29 /* Reference param save area */ |
969 | #endif | 963 | #endif |
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index e5d71905cad5..9d797ae4fa22 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c | |||
@@ -1258,7 +1258,7 @@ int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long | |||
1258 | * | 1258 | * |
1259 | * Retrieve the cpu number for the cpu at the specified HPA. | 1259 | * Retrieve the cpu number for the cpu at the specified HPA. |
1260 | */ | 1260 | */ |
1261 | int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa) | 1261 | int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, unsigned long hpa) |
1262 | { | 1262 | { |
1263 | int retval; | 1263 | int retval; |
1264 | unsigned long flags; | 1264 | unsigned long flags; |
diff --git a/arch/parisc/kernel/inventory.c b/arch/parisc/kernel/inventory.c index c05d1876d27c..c9789d9c73b4 100644 --- a/arch/parisc/kernel/inventory.c +++ b/arch/parisc/kernel/inventory.c | |||
@@ -216,9 +216,9 @@ pat_query_module(ulong pcell_loc, ulong mod_index) | |||
216 | register_parisc_device(dev); /* advertise device */ | 216 | register_parisc_device(dev); /* advertise device */ |
217 | 217 | ||
218 | #ifdef DEBUG_PAT | 218 | #ifdef DEBUG_PAT |
219 | pdc_pat_cell_mod_maddr_block_t io_pdc_cell; | ||
220 | /* dump what we see so far... */ | 219 | /* dump what we see so far... */ |
221 | switch (PAT_GET_ENTITY(dev->mod_info)) { | 220 | switch (PAT_GET_ENTITY(dev->mod_info)) { |
221 | pdc_pat_cell_mod_maddr_block_t io_pdc_cell; | ||
222 | unsigned long i; | 222 | unsigned long i; |
223 | 223 | ||
224 | case PAT_ENTITY_PROC: | 224 | case PAT_ENTITY_PROC: |
@@ -259,9 +259,9 @@ pat_query_module(ulong pcell_loc, ulong mod_index) | |||
259 | pa_pdc_cell->mod[4 + i * 3]); /* finish (ie end) */ | 259 | pa_pdc_cell->mod[4 + i * 3]); /* finish (ie end) */ |
260 | printk(KERN_DEBUG | 260 | printk(KERN_DEBUG |
261 | " IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", | 261 | " IO_VIEW %ld: 0x%016lx 0x%016lx 0x%016lx\n", |
262 | i, io_pdc_cell->mod[2 + i * 3], /* type */ | 262 | i, io_pdc_cell.mod[2 + i * 3], /* type */ |
263 | io_pdc_cell->mod[3 + i * 3], /* start */ | 263 | io_pdc_cell.mod[3 + i * 3], /* start */ |
264 | io_pdc_cell->mod[4 + i * 3]); /* finish (ie end) */ | 264 | io_pdc_cell.mod[4 + i * 3]); /* finish (ie end) */ |
265 | } | 265 | } |
266 | printk(KERN_DEBUG "\n"); | 266 | printk(KERN_DEBUG "\n"); |
267 | break; | 267 | break; |
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index 518f4f5f1f43..6eabce62463b 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c | |||
@@ -301,7 +301,6 @@ static ssize_t perf_read(struct file *file, char __user *buf, size_t cnt, loff_t | |||
301 | static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, | 301 | static ssize_t perf_write(struct file *file, const char __user *buf, size_t count, |
302 | loff_t *ppos) | 302 | loff_t *ppos) |
303 | { | 303 | { |
304 | int err; | ||
305 | size_t image_size; | 304 | size_t image_size; |
306 | uint32_t image_type; | 305 | uint32_t image_type; |
307 | uint32_t interface_type; | 306 | uint32_t interface_type; |
@@ -320,8 +319,8 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun | |||
320 | if (count != sizeof(uint32_t)) | 319 | if (count != sizeof(uint32_t)) |
321 | return -EIO; | 320 | return -EIO; |
322 | 321 | ||
323 | if ((err = copy_from_user(&image_type, buf, sizeof(uint32_t))) != 0) | 322 | if (copy_from_user(&image_type, buf, sizeof(uint32_t))) |
324 | return err; | 323 | return -EFAULT; |
325 | 324 | ||
326 | /* Get the interface type and test type */ | 325 | /* Get the interface type and test type */ |
327 | interface_type = (image_type >> 16) & 0xffff; | 326 | interface_type = (image_type >> 16) & 0xffff; |
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 40639439d8b3..ea6603ee8d24 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c | |||
@@ -276,11 +276,7 @@ void *dereference_function_descriptor(void *ptr) | |||
276 | 276 | ||
277 | static inline unsigned long brk_rnd(void) | 277 | static inline unsigned long brk_rnd(void) |
278 | { | 278 | { |
279 | /* 8MB for 32bit, 1GB for 64bit */ | 279 | return (get_random_int() & BRK_RND_MASK) << PAGE_SHIFT; |
280 | if (is_32bit_task()) | ||
281 | return (get_random_int() & 0x7ffUL) << PAGE_SHIFT; | ||
282 | else | ||
283 | return (get_random_int() & 0x3ffffUL) << PAGE_SHIFT; | ||
284 | } | 280 | } |
285 | 281 | ||
286 | unsigned long arch_randomize_brk(struct mm_struct *mm) | 282 | unsigned long arch_randomize_brk(struct mm_struct *mm) |
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c index 0c2a94a0f751..85de47f4eb59 100644 --- a/arch/parisc/kernel/processor.c +++ b/arch/parisc/kernel/processor.c | |||
@@ -78,11 +78,6 @@ DEFINE_PER_CPU(struct cpuinfo_parisc, cpu_data); | |||
78 | static void | 78 | static void |
79 | init_percpu_prof(unsigned long cpunum) | 79 | init_percpu_prof(unsigned long cpunum) |
80 | { | 80 | { |
81 | struct cpuinfo_parisc *p; | ||
82 | |||
83 | p = &per_cpu(cpu_data, cpunum); | ||
84 | p->prof_counter = 1; | ||
85 | p->prof_multiplier = 1; | ||
86 | } | 81 | } |
87 | 82 | ||
88 | 83 | ||
@@ -99,6 +94,7 @@ static int processor_probe(struct parisc_device *dev) | |||
99 | unsigned long txn_addr; | 94 | unsigned long txn_addr; |
100 | unsigned long cpuid; | 95 | unsigned long cpuid; |
101 | struct cpuinfo_parisc *p; | 96 | struct cpuinfo_parisc *p; |
97 | struct pdc_pat_cpu_num cpu_info __maybe_unused; | ||
102 | 98 | ||
103 | #ifdef CONFIG_SMP | 99 | #ifdef CONFIG_SMP |
104 | if (num_online_cpus() >= nr_cpu_ids) { | 100 | if (num_online_cpus() >= nr_cpu_ids) { |
@@ -123,10 +119,6 @@ static int processor_probe(struct parisc_device *dev) | |||
123 | ulong status; | 119 | ulong status; |
124 | unsigned long bytecnt; | 120 | unsigned long bytecnt; |
125 | pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell; | 121 | pdc_pat_cell_mod_maddr_block_t *pa_pdc_cell; |
126 | #undef USE_PAT_CPUID | ||
127 | #ifdef USE_PAT_CPUID | ||
128 | struct pdc_pat_cpu_num cpu_info; | ||
129 | #endif | ||
130 | 122 | ||
131 | pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL); | 123 | pa_pdc_cell = kmalloc(sizeof (*pa_pdc_cell), GFP_KERNEL); |
132 | if (!pa_pdc_cell) | 124 | if (!pa_pdc_cell) |
@@ -145,22 +137,27 @@ static int processor_probe(struct parisc_device *dev) | |||
145 | 137 | ||
146 | kfree(pa_pdc_cell); | 138 | kfree(pa_pdc_cell); |
147 | 139 | ||
140 | /* get the cpu number */ | ||
141 | status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa.start); | ||
142 | BUG_ON(PDC_OK != status); | ||
143 | |||
144 | pr_info("Logical CPU #%lu is physical cpu #%lu at location " | ||
145 | "0x%lx with hpa %pa\n", | ||
146 | cpuid, cpu_info.cpu_num, cpu_info.cpu_loc, | ||
147 | &dev->hpa.start); | ||
148 | |||
149 | #undef USE_PAT_CPUID | ||
148 | #ifdef USE_PAT_CPUID | 150 | #ifdef USE_PAT_CPUID |
149 | /* We need contiguous numbers for cpuid. Firmware's notion | 151 | /* We need contiguous numbers for cpuid. Firmware's notion |
150 | * of cpuid is for physical CPUs and we just don't care yet. | 152 | * of cpuid is for physical CPUs and we just don't care yet. |
151 | * We'll care when we need to query PAT PDC about a CPU *after* | 153 | * We'll care when we need to query PAT PDC about a CPU *after* |
152 | * boot time (ie shutdown a CPU from an OS perspective). | 154 | * boot time (ie shutdown a CPU from an OS perspective). |
153 | */ | 155 | */ |
154 | /* get the cpu number */ | ||
155 | status = pdc_pat_cpu_get_number(&cpu_info, dev->hpa.start); | ||
156 | |||
157 | BUG_ON(PDC_OK != status); | ||
158 | |||
159 | if (cpu_info.cpu_num >= NR_CPUS) { | 156 | if (cpu_info.cpu_num >= NR_CPUS) { |
160 | printk(KERN_WARNING "IGNORING CPU at 0x%x," | 157 | printk(KERN_WARNING "IGNORING CPU at %pa," |
161 | " cpu_slot_id > NR_CPUS" | 158 | " cpu_slot_id > NR_CPUS" |
162 | " (%ld > %d)\n", | 159 | " (%ld > %d)\n", |
163 | dev->hpa.start, cpu_info.cpu_num, NR_CPUS); | 160 | &dev->hpa.start, cpu_info.cpu_num, NR_CPUS); |
164 | /* Ignore CPU since it will only crash */ | 161 | /* Ignore CPU since it will only crash */ |
165 | boot_cpu_data.cpu_count--; | 162 | boot_cpu_data.cpu_count--; |
166 | return 1; | 163 | return 1; |
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index 0a393a04e891..a81e177cac7b 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c | |||
@@ -225,19 +225,17 @@ static unsigned long mmap_rnd(void) | |||
225 | { | 225 | { |
226 | unsigned long rnd = 0; | 226 | unsigned long rnd = 0; |
227 | 227 | ||
228 | /* | 228 | if (current->flags & PF_RANDOMIZE) |
229 | * 8 bits of randomness in 32bit mmaps, 20 address space bits | 229 | rnd = get_random_int() & MMAP_RND_MASK; |
230 | * 28 bits of randomness in 64bit mmaps, 40 address space bits | 230 | |
231 | */ | ||
232 | if (current->flags & PF_RANDOMIZE) { | ||
233 | if (is_32bit_task()) | ||
234 | rnd = get_random_int() % (1<<8); | ||
235 | else | ||
236 | rnd = get_random_int() % (1<<28); | ||
237 | } | ||
238 | return rnd << PAGE_SHIFT; | 231 | return rnd << PAGE_SHIFT; |
239 | } | 232 | } |
240 | 233 | ||
234 | unsigned long arch_mmap_rnd(void) | ||
235 | { | ||
236 | return (get_random_int() & MMAP_RND_MASK) << PAGE_SHIFT; | ||
237 | } | ||
238 | |||
241 | static unsigned long mmap_legacy_base(void) | 239 | static unsigned long mmap_legacy_base(void) |
242 | { | 240 | { |
243 | return TASK_UNMAPPED_BASE + mmap_rnd(); | 241 | return TASK_UNMAPPED_BASE + mmap_rnd(); |
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 325f30d82b64..4215f5596c8b 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c | |||
@@ -59,10 +59,9 @@ static unsigned long clocktick __read_mostly; /* timer cycles per tick */ | |||
59 | */ | 59 | */ |
60 | irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) | 60 | irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) |
61 | { | 61 | { |
62 | unsigned long now, now2; | 62 | unsigned long now; |
63 | unsigned long next_tick; | 63 | unsigned long next_tick; |
64 | unsigned long cycles_elapsed, ticks_elapsed = 1; | 64 | unsigned long ticks_elapsed = 0; |
65 | unsigned long cycles_remainder; | ||
66 | unsigned int cpu = smp_processor_id(); | 65 | unsigned int cpu = smp_processor_id(); |
67 | struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); | 66 | struct cpuinfo_parisc *cpuinfo = &per_cpu(cpu_data, cpu); |
68 | 67 | ||
@@ -71,102 +70,49 @@ irqreturn_t __irq_entry timer_interrupt(int irq, void *dev_id) | |||
71 | 70 | ||
72 | profile_tick(CPU_PROFILING); | 71 | profile_tick(CPU_PROFILING); |
73 | 72 | ||
74 | /* Initialize next_tick to the expected tick time. */ | 73 | /* Initialize next_tick to the old expected tick time. */ |
75 | next_tick = cpuinfo->it_value; | 74 | next_tick = cpuinfo->it_value; |
76 | 75 | ||
77 | /* Get current cycle counter (Control Register 16). */ | 76 | /* Calculate how many ticks have elapsed. */ |
78 | now = mfctl(16); | 77 | do { |
79 | 78 | ++ticks_elapsed; | |
80 | cycles_elapsed = now - next_tick; | 79 | next_tick += cpt; |
81 | 80 | now = mfctl(16); | |
82 | if ((cycles_elapsed >> 6) < cpt) { | 81 | } while (next_tick - now > cpt); |
83 | /* use "cheap" math (add/subtract) instead | ||
84 | * of the more expensive div/mul method | ||
85 | */ | ||
86 | cycles_remainder = cycles_elapsed; | ||
87 | while (cycles_remainder > cpt) { | ||
88 | cycles_remainder -= cpt; | ||
89 | ticks_elapsed++; | ||
90 | } | ||
91 | } else { | ||
92 | /* TODO: Reduce this to one fdiv op */ | ||
93 | cycles_remainder = cycles_elapsed % cpt; | ||
94 | ticks_elapsed += cycles_elapsed / cpt; | ||
95 | } | ||
96 | |||
97 | /* convert from "division remainder" to "remainder of clock tick" */ | ||
98 | cycles_remainder = cpt - cycles_remainder; | ||
99 | |||
100 | /* Determine when (in CR16 cycles) next IT interrupt will fire. | ||
101 | * We want IT to fire modulo clocktick even if we miss/skip some. | ||
102 | * But those interrupts don't in fact get delivered that regularly. | ||
103 | */ | ||
104 | next_tick = now + cycles_remainder; | ||
105 | 82 | ||
83 | /* Store (in CR16 cycles) up to when we are accounting right now. */ | ||
106 | cpuinfo->it_value = next_tick; | 84 | cpuinfo->it_value = next_tick; |
107 | 85 | ||
108 | /* Program the IT when to deliver the next interrupt. | 86 | /* Go do system house keeping. */ |
109 | * Only bottom 32-bits of next_tick are writable in CR16! | 87 | if (cpu == 0) |
110 | */ | 88 | xtime_update(ticks_elapsed); |
111 | mtctl(next_tick, 16); | 89 | |
90 | update_process_times(user_mode(get_irq_regs())); | ||
112 | 91 | ||
113 | /* Skip one clocktick on purpose if we missed next_tick. | 92 | /* Skip clockticks on purpose if we know we would miss those. |
114 | * The new CR16 must be "later" than current CR16 otherwise | 93 | * The new CR16 must be "later" than current CR16 otherwise |
115 | * itimer would not fire until CR16 wrapped - e.g 4 seconds | 94 | * itimer would not fire until CR16 wrapped - e.g 4 seconds |
116 | * later on a 1Ghz processor. We'll account for the missed | 95 | * later on a 1Ghz processor. We'll account for the missed |
117 | * tick on the next timer interrupt. | 96 | * ticks on the next timer interrupt. |
97 | * We want IT to fire modulo clocktick even if we miss/skip some. | ||
98 | * But those interrupts don't in fact get delivered that regularly. | ||
118 | * | 99 | * |
119 | * "next_tick - now" will always give the difference regardless | 100 | * "next_tick - now" will always give the difference regardless |
120 | * if one or the other wrapped. If "now" is "bigger" we'll end up | 101 | * if one or the other wrapped. If "now" is "bigger" we'll end up |
121 | * with a very large unsigned number. | 102 | * with a very large unsigned number. |
122 | */ | 103 | */ |
123 | now2 = mfctl(16); | 104 | while (next_tick - mfctl(16) > cpt) |
124 | if (next_tick - now2 > cpt) | 105 | next_tick += cpt; |
125 | mtctl(next_tick+cpt, 16); | ||
126 | 106 | ||
127 | #if 1 | 107 | /* Program the IT when to deliver the next interrupt. |
128 | /* | 108 | * Only bottom 32-bits of next_tick are writable in CR16! |
129 | * GGG: DEBUG code for how many cycles programming CR16 used. | 109 | * Timer interrupt will be delivered at least a few hundred cycles |
130 | */ | 110 | * after the IT fires, so if we are too close (<= 500 cycles) to the |
131 | if (unlikely(now2 - now > 0x3000)) /* 12K cycles */ | 111 | * next cycle, simply skip it. |
132 | printk (KERN_CRIT "timer_interrupt(CPU %d): SLOW! 0x%lx cycles!" | ||
133 | " cyc %lX rem %lX " | ||
134 | " next/now %lX/%lX\n", | ||
135 | cpu, now2 - now, cycles_elapsed, cycles_remainder, | ||
136 | next_tick, now ); | ||
137 | #endif | ||
138 | |||
139 | /* Can we differentiate between "early CR16" (aka Scenario 1) and | ||
140 | * "long delay" (aka Scenario 3)? I don't think so. | ||
141 | * | ||
142 | * Timer_interrupt will be delivered at least a few hundred cycles | ||
143 | * after the IT fires. But it's arbitrary how much time passes | ||
144 | * before we call it "late". I've picked one second. | ||
145 | * | ||
146 | * It's important NO printk's are between reading CR16 and | ||
147 | * setting up the next value. May introduce huge variance. | ||
148 | */ | ||
149 | if (unlikely(ticks_elapsed > HZ)) { | ||
150 | /* Scenario 3: very long delay? bad in any case */ | ||
151 | printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!" | ||
152 | " cycles %lX rem %lX " | ||
153 | " next/now %lX/%lX\n", | ||
154 | cpu, | ||
155 | cycles_elapsed, cycles_remainder, | ||
156 | next_tick, now ); | ||
157 | } | ||
158 | |||
159 | /* Done mucking with unreliable delivery of interrupts. | ||
160 | * Go do system house keeping. | ||
161 | */ | 112 | */ |
162 | 113 | if (next_tick - mfctl(16) <= 500) | |
163 | if (!--cpuinfo->prof_counter) { | 114 | next_tick += cpt; |
164 | cpuinfo->prof_counter = cpuinfo->prof_multiplier; | 115 | mtctl(next_tick, 16); |
165 | update_process_times(user_mode(get_irq_regs())); | ||
166 | } | ||
167 | |||
168 | if (cpu == 0) | ||
169 | xtime_update(ticks_elapsed); | ||
170 | 116 | ||
171 | return IRQ_HANDLED; | 117 | return IRQ_HANDLED; |
172 | } | 118 | } |