7d12e780e0
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead of passing regs around manually through all ~1800 interrupt handlers in the Linux kernel. The regs pointer is used in few places, but it potentially costs both stack space and code to pass it around. On the FRV arch, removing the regs parameter from all the genirq function results in a 20% speed up of the IRQ exit path (ie: from leaving timer_interrupt() to leaving do_IRQ()). Where appropriate, an arch may override the generic storage facility and do something different with the variable. On FRV, for instance, the address is maintained in GR28 at all times inside the kernel as part of general exception handling. Having looked over the code, it appears that the parameter may be handed down through up to twenty or so layers of functions. Consider a USB character device attached to a USB hub, attached to a USB controller that posts its interrupts through a cascaded auxiliary interrupt controller. A character device driver may want to pass regs to the sysrq handler through the input layer which adds another few layers of parameter passing. I've build this code with allyesconfig for x86_64 and i386. I've runtested the main part of the code on FRV and i386, though I can't test most of the drivers. I've also done partial conversion for powerpc and MIPS - these at least compile with minimal configurations. This will affect all archs. Mostly the changes should be relatively easy. Take do_IRQ(), store the regs pointer at the beginning, saving the old one: struct pt_regs *old_regs = set_irq_regs(regs); And put the old one back at the end: set_irq_regs(old_regs); Don't pass regs through to generic_handle_irq() or __do_IRQ(). In timer_interrupt(), this sort of change will be necessary: - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING, regs); + update_process_times(user_mode(get_irq_regs())); + profile_tick(CPU_PROFILING); I'd like to move update_process_times()'s use of get_irq_regs() into itself, except that i386, alone of the archs, uses something other than user_mode(). Some notes on the interrupt handling in the drivers: (*) input_dev() is now gone entirely. The regs pointer is no longer stored in the input_dev struct. (*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does something different depending on whether it's been supplied with a regs pointer or not. (*) Various IRQ handler function pointers have been moved to type irq_handler_t. Signed-Off-By: David Howells <dhowells@redhat.com> (cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
135 lines
3.5 KiB
C
135 lines
3.5 KiB
C
#ifndef _ASM_X8664_PROTO_H
|
|
#define _ASM_X8664_PROTO_H 1
|
|
|
|
#include <asm/ldt.h>
|
|
|
|
/* misc architecture specific prototypes */
|
|
|
|
struct cpuinfo_x86;
|
|
struct pt_regs;
|
|
|
|
extern void start_kernel(void);
|
|
extern void pda_init(int);
|
|
|
|
extern void zap_low_mappings(int cpu);
|
|
|
|
extern void early_idt_handler(void);
|
|
|
|
extern void mcheck_init(struct cpuinfo_x86 *c);
|
|
#ifdef CONFIG_MTRR
|
|
extern void mtrr_ap_init(void);
|
|
extern void mtrr_bp_init(void);
|
|
#else
|
|
#define mtrr_ap_init() do {} while (0)
|
|
#define mtrr_bp_init() do {} while (0)
|
|
#endif
|
|
extern void init_memory_mapping(unsigned long start, unsigned long end);
|
|
|
|
extern void system_call(void);
|
|
extern int kernel_syscall(void);
|
|
extern void syscall_init(void);
|
|
|
|
extern void ia32_syscall(void);
|
|
extern void ia32_cstar_target(void);
|
|
extern void ia32_sysenter_target(void);
|
|
|
|
extern void config_acpi_tables(void);
|
|
extern void ia32_syscall(void);
|
|
|
|
extern int pmtimer_mark_offset(void);
|
|
extern void pmtimer_resume(void);
|
|
extern void pmtimer_wait(unsigned);
|
|
extern unsigned int do_gettimeoffset_pm(void);
|
|
#ifdef CONFIG_X86_PM_TIMER
|
|
extern u32 pmtmr_ioport;
|
|
#else
|
|
#define pmtmr_ioport 0
|
|
#endif
|
|
extern unsigned long long monotonic_base;
|
|
extern int sysctl_vsyscall;
|
|
extern int nohpet;
|
|
extern unsigned long vxtime_hz;
|
|
extern void time_init_gtod(void);
|
|
|
|
extern void early_printk(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
|
|
|
extern void early_identify_cpu(struct cpuinfo_x86 *c);
|
|
|
|
extern int k8_scan_nodes(unsigned long start, unsigned long end);
|
|
|
|
extern void numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn);
|
|
extern unsigned long numa_free_all_bootmem(void);
|
|
|
|
extern void reserve_bootmem_generic(unsigned long phys, unsigned len);
|
|
extern void free_bootmem_generic(unsigned long phys, unsigned len);
|
|
|
|
extern void load_gs_index(unsigned gs);
|
|
|
|
extern void stop_timer_interrupt(void);
|
|
extern void main_timer_handler(void);
|
|
|
|
extern unsigned long end_pfn_map;
|
|
|
|
extern void show_trace(struct task_struct *, struct pt_regs *, unsigned long * rsp);
|
|
extern void show_registers(struct pt_regs *regs);
|
|
|
|
extern void exception_table_check(void);
|
|
|
|
extern void acpi_reserve_bootmem(void);
|
|
|
|
extern void swap_low_mappings(void);
|
|
|
|
extern void __show_regs(struct pt_regs * regs);
|
|
extern void show_regs(struct pt_regs * regs);
|
|
|
|
extern char *syscall32_page;
|
|
extern void syscall32_cpu_init(void);
|
|
|
|
extern void setup_node_bootmem(int nodeid, unsigned long start, unsigned long end);
|
|
|
|
extern void early_quirks(void);
|
|
extern void check_efer(void);
|
|
|
|
extern int unhandled_signal(struct task_struct *tsk, int sig);
|
|
|
|
extern int unsynchronized_tsc(void);
|
|
|
|
extern void select_idle_routine(const struct cpuinfo_x86 *c);
|
|
|
|
extern unsigned long table_start, table_end;
|
|
|
|
extern int exception_trace;
|
|
extern unsigned cpu_khz;
|
|
|
|
extern void no_iommu_init(void);
|
|
extern int force_iommu, no_iommu;
|
|
extern int iommu_detected;
|
|
#ifdef CONFIG_IOMMU
|
|
extern void gart_iommu_init(void);
|
|
extern void gart_parse_options(char *);
|
|
extern void iommu_hole_init(void);
|
|
extern int fallback_aper_order;
|
|
extern int fallback_aper_force;
|
|
extern int iommu_aperture;
|
|
extern int iommu_aperture_allowed;
|
|
extern int iommu_aperture_disabled;
|
|
extern int fix_aperture;
|
|
#else
|
|
#define iommu_aperture 0
|
|
#define iommu_aperture_allowed 0
|
|
#endif
|
|
|
|
extern int reboot_force;
|
|
extern int notsc_setup(char *);
|
|
|
|
extern int gsi_irq_sharing(int gsi);
|
|
|
|
extern void smp_local_timer_interrupt(void);
|
|
|
|
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
|
|
|
|
#define round_up(x,y) (((x) + (y) - 1) & ~((y)-1))
|
|
#define round_down(x,y) ((x) & ~((y)-1))
|
|
|
|
#endif
|