mirror of
https://github.com/torvalds/linux.git
synced 2024-11-18 01:51:53 +00:00
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)
157 lines
4.0 KiB
C
157 lines
4.0 KiB
C
/* orinoco.h
|
|
*
|
|
* Common definitions to all pieces of the various orinoco
|
|
* drivers
|
|
*/
|
|
|
|
#ifndef _ORINOCO_H
|
|
#define _ORINOCO_H
|
|
|
|
#define DRIVER_VERSION "0.15"
|
|
|
|
#include <linux/netdevice.h>
|
|
#include <linux/wireless.h>
|
|
#include <net/iw_handler.h>
|
|
|
|
#include "hermes.h"
|
|
|
|
/* To enable debug messages */
|
|
//#define ORINOCO_DEBUG 3
|
|
|
|
#define WIRELESS_SPY // enable iwspy support
|
|
|
|
#define MAX_SCAN_LEN 4096
|
|
|
|
#define ORINOCO_MAX_KEY_SIZE 14
|
|
#define ORINOCO_MAX_KEYS 4
|
|
|
|
struct orinoco_key {
|
|
__le16 len; /* always stored as little-endian */
|
|
char data[ORINOCO_MAX_KEY_SIZE];
|
|
} __attribute__ ((packed));
|
|
|
|
typedef enum {
|
|
FIRMWARE_TYPE_AGERE,
|
|
FIRMWARE_TYPE_INTERSIL,
|
|
FIRMWARE_TYPE_SYMBOL
|
|
} fwtype_t;
|
|
|
|
struct orinoco_private {
|
|
void *card; /* Pointer to card dependent structure */
|
|
int (*hard_reset)(struct orinoco_private *);
|
|
|
|
/* Synchronisation stuff */
|
|
spinlock_t lock;
|
|
int hw_unavailable;
|
|
struct work_struct reset_work;
|
|
|
|
/* driver state */
|
|
int open;
|
|
u16 last_linkstatus;
|
|
struct work_struct join_work;
|
|
struct work_struct wevent_work;
|
|
|
|
/* Net device stuff */
|
|
struct net_device *ndev;
|
|
struct net_device_stats stats;
|
|
struct iw_statistics wstats;
|
|
|
|
/* Hardware control variables */
|
|
hermes_t hw;
|
|
u16 txfid;
|
|
|
|
/* Capabilities of the hardware/firmware */
|
|
fwtype_t firmware_type;
|
|
char fw_name[32];
|
|
int ibss_port;
|
|
int nicbuf_size;
|
|
u16 channel_mask;
|
|
|
|
/* Boolean capabilities */
|
|
unsigned int has_ibss:1;
|
|
unsigned int has_port3:1;
|
|
unsigned int has_wep:1;
|
|
unsigned int has_big_wep:1;
|
|
unsigned int has_mwo:1;
|
|
unsigned int has_pm:1;
|
|
unsigned int has_preamble:1;
|
|
unsigned int has_sensitivity:1;
|
|
unsigned int has_hostscan:1;
|
|
unsigned int broken_disableport:1;
|
|
unsigned int broken_monitor:1;
|
|
|
|
/* Configuration paramaters */
|
|
u32 iw_mode;
|
|
int prefer_port3;
|
|
u16 wep_on, wep_restrict, tx_key;
|
|
struct orinoco_key keys[ORINOCO_MAX_KEYS];
|
|
int bitratemode;
|
|
char nick[IW_ESSID_MAX_SIZE+1];
|
|
char desired_essid[IW_ESSID_MAX_SIZE+1];
|
|
char desired_bssid[ETH_ALEN];
|
|
int bssid_fixed;
|
|
u16 frag_thresh, mwo_robust;
|
|
u16 channel;
|
|
u16 ap_density, rts_thresh;
|
|
u16 pm_on, pm_mcast, pm_period, pm_timeout;
|
|
u16 preamble;
|
|
#ifdef WIRELESS_SPY
|
|
struct iw_spy_data spy_data; /* iwspy support */
|
|
struct iw_public_data wireless_data;
|
|
#endif
|
|
|
|
/* Configuration dependent variables */
|
|
int port_type, createibss;
|
|
int promiscuous, mc_count;
|
|
|
|
/* Scanning support */
|
|
int scan_inprogress; /* Scan pending... */
|
|
u32 scan_mode; /* Type of scan done */
|
|
char * scan_result; /* Result of previous scan */
|
|
int scan_len; /* Lenght of result */
|
|
};
|
|
|
|
#ifdef ORINOCO_DEBUG
|
|
extern int orinoco_debug;
|
|
#define DEBUG(n, args...) do { if (orinoco_debug>(n)) printk(KERN_DEBUG args); } while(0)
|
|
#else
|
|
#define DEBUG(n, args...) do { } while (0)
|
|
#endif /* ORINOCO_DEBUG */
|
|
|
|
/********************************************************************/
|
|
/* Exported prototypes */
|
|
/********************************************************************/
|
|
|
|
extern struct net_device *alloc_orinocodev(int sizeof_card,
|
|
int (*hard_reset)(struct orinoco_private *));
|
|
extern void free_orinocodev(struct net_device *dev);
|
|
extern int __orinoco_up(struct net_device *dev);
|
|
extern int __orinoco_down(struct net_device *dev);
|
|
extern int orinoco_reinit_firmware(struct net_device *dev);
|
|
extern irqreturn_t orinoco_interrupt(int irq, void * dev_id);
|
|
|
|
/********************************************************************/
|
|
/* Locking and synchronization functions */
|
|
/********************************************************************/
|
|
|
|
static inline int orinoco_lock(struct orinoco_private *priv,
|
|
unsigned long *flags)
|
|
{
|
|
spin_lock_irqsave(&priv->lock, *flags);
|
|
if (priv->hw_unavailable) {
|
|
DEBUG(1, "orinoco_lock() called with hw_unavailable (dev=%p)\n",
|
|
priv->ndev);
|
|
spin_unlock_irqrestore(&priv->lock, *flags);
|
|
return -EBUSY;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static inline void orinoco_unlock(struct orinoco_private *priv,
|
|
unsigned long *flags)
|
|
{
|
|
spin_unlock_irqrestore(&priv->lock, *flags);
|
|
}
|
|
|
|
#endif /* _ORINOCO_H */
|