mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 18:30:06 +00:00
![David Howells](/assets/img/avatar_default.png)
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)
134 lines
5.7 KiB
C
134 lines
5.7 KiB
C
#ifndef _LINUX_XD_H
|
|
#define _LINUX_XD_H
|
|
|
|
/*
|
|
* This file contains the definitions for the IO ports and errors etc. for XT hard disk controllers (at least the DTC 5150X).
|
|
*
|
|
* Author: Pat Mackinlay, pat@it.com.au
|
|
* Date: 29/09/92
|
|
*
|
|
* Revised: 01/01/93, ...
|
|
*
|
|
* Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com)
|
|
* Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
|
|
*/
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
/* XT hard disk controller registers */
|
|
#define XD_DATA (xd_iobase + 0x00) /* data RW register */
|
|
#define XD_RESET (xd_iobase + 0x01) /* reset WO register */
|
|
#define XD_STATUS (xd_iobase + 0x01) /* status RO register */
|
|
#define XD_SELECT (xd_iobase + 0x02) /* select WO register */
|
|
#define XD_JUMPER (xd_iobase + 0x02) /* jumper RO register */
|
|
#define XD_CONTROL (xd_iobase + 0x03) /* DMAE/INTE WO register */
|
|
#define XD_RESERVED (xd_iobase + 0x03) /* reserved */
|
|
|
|
/* XT hard disk controller commands (incomplete list) */
|
|
#define CMD_TESTREADY 0x00 /* test drive ready */
|
|
#define CMD_RECALIBRATE 0x01 /* recalibrate drive */
|
|
#define CMD_SENSE 0x03 /* request sense */
|
|
#define CMD_FORMATDRV 0x04 /* format drive */
|
|
#define CMD_VERIFY 0x05 /* read verify */
|
|
#define CMD_FORMATTRK 0x06 /* format track */
|
|
#define CMD_FORMATBAD 0x07 /* format bad track */
|
|
#define CMD_READ 0x08 /* read */
|
|
#define CMD_WRITE 0x0A /* write */
|
|
#define CMD_SEEK 0x0B /* seek */
|
|
|
|
/* Controller specific commands */
|
|
#define CMD_DTCSETPARAM 0x0C /* set drive parameters (DTC 5150X & CX only?) */
|
|
#define CMD_DTCGETECC 0x0D /* get ecc error length (DTC 5150X only?) */
|
|
#define CMD_DTCREADBUF 0x0E /* read sector buffer (DTC 5150X only?) */
|
|
#define CMD_DTCWRITEBUF 0x0F /* write sector buffer (DTC 5150X only?) */
|
|
#define CMD_DTCREMAPTRK 0x11 /* assign alternate track (DTC 5150X only?) */
|
|
#define CMD_DTCGETPARAM 0xFB /* get drive parameters (DTC 5150X only?) */
|
|
#define CMD_DTCSETSTEP 0xFC /* set step rate (DTC 5150X only?) */
|
|
#define CMD_DTCSETGEOM 0xFE /* set geometry data (DTC 5150X only?) */
|
|
#define CMD_DTCGETGEOM 0xFF /* get geometry data (DTC 5150X only?) */
|
|
#define CMD_ST11GETGEOM 0xF8 /* get geometry data (Seagate ST11R/M only?) */
|
|
#define CMD_WDSETPARAM 0x0C /* set drive parameters (WD 1004A27X only?) */
|
|
#define CMD_XBSETPARAM 0x0C /* set drive parameters (XEBEC only?) */
|
|
|
|
/* Bits for command status byte */
|
|
#define CSB_ERROR 0x02 /* error */
|
|
#define CSB_LUN 0x20 /* logical Unit Number */
|
|
|
|
/* XT hard disk controller status bits */
|
|
#define STAT_READY 0x01 /* controller is ready */
|
|
#define STAT_INPUT 0x02 /* data flowing from controller to host */
|
|
#define STAT_COMMAND 0x04 /* controller in command phase */
|
|
#define STAT_SELECT 0x08 /* controller is selected */
|
|
#define STAT_REQUEST 0x10 /* controller requesting data */
|
|
#define STAT_INTERRUPT 0x20 /* controller requesting interrupt */
|
|
|
|
/* XT hard disk controller control bits */
|
|
#define PIO_MODE 0x00 /* control bits to set for PIO */
|
|
#define DMA_MODE 0x03 /* control bits to set for DMA & interrupt */
|
|
|
|
#define XD_MAXDRIVES 2 /* maximum 2 drives */
|
|
#define XD_TIMEOUT HZ /* 1 second timeout */
|
|
#define XD_RETRIES 4 /* maximum 4 retries */
|
|
|
|
#undef DEBUG /* define for debugging output */
|
|
|
|
#ifdef DEBUG
|
|
#define DEBUG_STARTUP /* debug driver initialisation */
|
|
#define DEBUG_OVERRIDE /* debug override geometry detection */
|
|
#define DEBUG_READWRITE /* debug each read/write command */
|
|
#define DEBUG_OTHER /* debug misc. interrupt/DMA stuff */
|
|
#define DEBUG_COMMAND /* debug each controller command */
|
|
#endif /* DEBUG */
|
|
|
|
/* this structure defines the XT drives and their types */
|
|
typedef struct {
|
|
u_char heads;
|
|
u_short cylinders;
|
|
u_char sectors;
|
|
u_char control;
|
|
int unit;
|
|
} XD_INFO;
|
|
|
|
/* this structure defines a ROM BIOS signature */
|
|
typedef struct {
|
|
unsigned int offset;
|
|
const char *string;
|
|
void (*init_controller)(unsigned int address);
|
|
void (*init_drive)(u_char drive);
|
|
const char *name;
|
|
} XD_SIGNATURE;
|
|
|
|
#ifndef MODULE
|
|
static int xd_manual_geo_init (char *command);
|
|
#endif /* MODULE */
|
|
static u_char xd_detect (u_char *controller, unsigned int *address);
|
|
static u_char xd_initdrives (void (*init_drive)(u_char drive));
|
|
|
|
static void do_xd_request (request_queue_t * q);
|
|
static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg);
|
|
static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count);
|
|
static void xd_recalibrate (u_char drive);
|
|
|
|
static irqreturn_t xd_interrupt_handler(int irq, void *dev_id);
|
|
static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
|
|
static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
|
|
static void xd_watchdog (unsigned long unused);
|
|
static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout);
|
|
static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
|
|
|
|
/* card specific setup and geometry gathering code */
|
|
static void xd_dtc_init_controller (unsigned int address);
|
|
static void xd_dtc5150cx_init_drive (u_char drive);
|
|
static void xd_dtc_init_drive (u_char drive);
|
|
static void xd_wd_init_controller (unsigned int address);
|
|
static void xd_wd_init_drive (u_char drive);
|
|
static void xd_seagate_init_controller (unsigned int address);
|
|
static void xd_seagate_init_drive (u_char drive);
|
|
static void xd_omti_init_controller (unsigned int address);
|
|
static void xd_omti_init_drive (u_char drive);
|
|
static void xd_xebec_init_controller (unsigned int address);
|
|
static void xd_xebec_init_drive (u_char drive);
|
|
static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
|
|
static void xd_override_init_drive (u_char drive);
|
|
|
|
#endif /* _LINUX_XD_H */
|