diff options
Diffstat (limited to 'include/linux/irq.h')
| -rw-r--r-- | include/linux/irq.h | 369 | 
1 files changed, 299 insertions, 70 deletions
| diff --git a/include/linux/irq.h b/include/linux/irq.h index abde2527c69..1d3577f30d4 100644 --- a/include/linux/irq.h +++ b/include/linux/irq.h @@ -29,60 +29,104 @@  #include <asm/irq_regs.h>  struct irq_desc; +struct irq_data;  typedef	void (*irq_flow_handler_t)(unsigned int irq,  					    struct irq_desc *desc); - +typedef	void (*irq_preflow_handler_t)(struct irq_data *data);  /*   * IRQ line status.   * - * Bits 0-7 are reserved for the IRQF_* bits in linux/interrupt.h + * Bits 0-7 are the same as the IRQF_* bits in linux/interrupt.h + * + * IRQ_TYPE_NONE		- default, unspecified type + * IRQ_TYPE_EDGE_RISING		- rising edge triggered + * IRQ_TYPE_EDGE_FALLING	- falling edge triggered + * IRQ_TYPE_EDGE_BOTH		- rising and falling edge triggered + * IRQ_TYPE_LEVEL_HIGH		- high level triggered + * IRQ_TYPE_LEVEL_LOW		- low level triggered + * IRQ_TYPE_LEVEL_MASK		- Mask to filter out the level bits + * IRQ_TYPE_SENSE_MASK		- Mask for all the above bits + * IRQ_TYPE_PROBE		- Special flag for probing in progress + * + * Bits which can be modified via irq_set/clear/modify_status_flags() + * IRQ_LEVEL			- Interrupt is level type. Will be also + *				  updated in the code when the above trigger + *				  bits are modified via set_irq_type() + * IRQ_PER_CPU			- Mark an interrupt PER_CPU. Will protect + *				  it from affinity setting + * IRQ_NOPROBE			- Interrupt cannot be probed by autoprobing + * IRQ_NOREQUEST		- Interrupt cannot be requested via + *				  request_irq() + * IRQ_NOAUTOEN			- Interrupt is not automatically enabled in + *				  request/setup_irq() + * IRQ_NO_BALANCING		- Interrupt cannot be balanced (affinity set) + * IRQ_MOVE_PCNTXT		- Interrupt can be migrated from process context + * IRQ_NESTED_TRHEAD		- Interrupt nests into another thread + * + * Deprecated bits. They are kept updated as long as + * CONFIG_GENERIC_HARDIRQS_NO_COMPAT is not set. Will go away soon. These bits + * are internal state of the core code and if you really need to acces + * them then talk to the genirq maintainer instead of hacking + * something weird.   * - * IRQ types   */ -#define IRQ_TYPE_NONE		0x00000000	/* Default, unspecified type */ -#define IRQ_TYPE_EDGE_RISING	0x00000001	/* Edge rising type */ -#define IRQ_TYPE_EDGE_FALLING	0x00000002	/* Edge falling type */ -#define IRQ_TYPE_EDGE_BOTH (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING) -#define IRQ_TYPE_LEVEL_HIGH	0x00000004	/* Level high type */ -#define IRQ_TYPE_LEVEL_LOW	0x00000008	/* Level low type */ -#define IRQ_TYPE_SENSE_MASK	0x0000000f	/* Mask of the above */ -#define IRQ_TYPE_PROBE		0x00000010	/* Probing in progress */ - -/* Internal flags */ -#define IRQ_INPROGRESS		0x00000100	/* IRQ handler active - do not enter! */ -#define IRQ_DISABLED		0x00000200	/* IRQ disabled - do not enter! */ -#define IRQ_PENDING		0x00000400	/* IRQ pending - replay on enable */ -#define IRQ_REPLAY		0x00000800	/* IRQ has been replayed but not acked yet */ -#define IRQ_AUTODETECT		0x00001000	/* IRQ is being autodetected */ -#define IRQ_WAITING		0x00002000	/* IRQ not yet seen - for autodetection */ -#define IRQ_LEVEL		0x00004000	/* IRQ level triggered */ -#define IRQ_MASKED		0x00008000	/* IRQ masked - shouldn't be seen again */ -#define IRQ_PER_CPU		0x00010000	/* IRQ is per CPU */ -#define IRQ_NOPROBE		0x00020000	/* IRQ is not valid for probing */ -#define IRQ_NOREQUEST		0x00040000	/* IRQ cannot be requested */ -#define IRQ_NOAUTOEN		0x00080000	/* IRQ will not be enabled on request irq */ -#define IRQ_WAKEUP		0x00100000	/* IRQ triggers system wakeup */ -#define IRQ_MOVE_PENDING	0x00200000	/* need to re-target IRQ destination */ -#define IRQ_NO_BALANCING	0x00400000	/* IRQ is excluded from balancing */ -#define IRQ_SPURIOUS_DISABLED	0x00800000	/* IRQ was disabled by the spurious trap */ -#define IRQ_MOVE_PCNTXT		0x01000000	/* IRQ migration from process context */ -#define IRQ_AFFINITY_SET	0x02000000	/* IRQ affinity was set from userspace*/ -#define IRQ_SUSPENDED		0x04000000	/* IRQ has gone through suspend sequence */ -#define IRQ_ONESHOT		0x08000000	/* IRQ is not unmasked after hardirq */ -#define IRQ_NESTED_THREAD	0x10000000	/* IRQ is nested into another, no own handler thread */ +enum { +	IRQ_TYPE_NONE		= 0x00000000, +	IRQ_TYPE_EDGE_RISING	= 0x00000001, +	IRQ_TYPE_EDGE_FALLING	= 0x00000002, +	IRQ_TYPE_EDGE_BOTH	= (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING), +	IRQ_TYPE_LEVEL_HIGH	= 0x00000004, +	IRQ_TYPE_LEVEL_LOW	= 0x00000008, +	IRQ_TYPE_LEVEL_MASK	= (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH), +	IRQ_TYPE_SENSE_MASK	= 0x0000000f, + +	IRQ_TYPE_PROBE		= 0x00000010, + +	IRQ_LEVEL		= (1 <<  8), +	IRQ_PER_CPU		= (1 <<  9), +	IRQ_NOPROBE		= (1 << 10), +	IRQ_NOREQUEST		= (1 << 11), +	IRQ_NOAUTOEN		= (1 << 12), +	IRQ_NO_BALANCING	= (1 << 13), +	IRQ_MOVE_PCNTXT		= (1 << 14), +	IRQ_NESTED_THREAD	= (1 << 15), + +#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT +	IRQ_INPROGRESS		= (1 << 16), +	IRQ_REPLAY		= (1 << 17), +	IRQ_WAITING		= (1 << 18), +	IRQ_DISABLED		= (1 << 19), +	IRQ_PENDING		= (1 << 20), +	IRQ_MASKED		= (1 << 21), +	IRQ_MOVE_PENDING	= (1 << 22), +	IRQ_AFFINITY_SET	= (1 << 23), +	IRQ_WAKEUP		= (1 << 24), +#endif +};  #define IRQF_MODIFY_MASK	\  	(IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \ -	 IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL) +	 IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \ +	 IRQ_PER_CPU | IRQ_NESTED_THREAD) -#ifdef CONFIG_IRQ_PER_CPU -# define CHECK_IRQ_PER_CPU(var) ((var) & IRQ_PER_CPU) -# define IRQ_NO_BALANCING_MASK	(IRQ_PER_CPU | IRQ_NO_BALANCING) -#else -# define CHECK_IRQ_PER_CPU(var) 0 -# define IRQ_NO_BALANCING_MASK	IRQ_NO_BALANCING -#endif +#define IRQ_NO_BALANCING_MASK	(IRQ_PER_CPU | IRQ_NO_BALANCING) + +static inline __deprecated bool CHECK_IRQ_PER_CPU(unsigned int status) +{ +	return status & IRQ_PER_CPU; +} + +/* + * Return value for chip->irq_set_affinity() + * + * IRQ_SET_MASK_OK	- OK, core updates irq_data.affinity + * IRQ_SET_MASK_NOCPY	- OK, chip did update irq_data.affinity + */ +enum { +	IRQ_SET_MASK_OK = 0, +	IRQ_SET_MASK_OK_NOCOPY, +};  struct msi_desc; @@ -90,6 +134,8 @@ struct msi_desc;   * struct irq_data - per irq and irq chip data passed down to chip functions   * @irq:		interrupt number   * @node:		node index useful for balancing + * @state_use_accessor: status information for irq chip functions. + *			Use accessor functions to deal with it   * @chip:		low level interrupt hardware access   * @handler_data:	per-IRQ data for the irq_chip methods   * @chip_data:		platform-specific per-chip private data for the chip @@ -104,6 +150,7 @@ struct msi_desc;  struct irq_data {  	unsigned int		irq;  	unsigned int		node; +	unsigned int		state_use_accessors;  	struct irq_chip		*chip;  	void			*handler_data;  	void			*chip_data; @@ -113,6 +160,80 @@ struct irq_data {  #endif  }; +/* + * Bit masks for irq_data.state + * + * IRQD_TRIGGER_MASK		- Mask for the trigger type bits + * IRQD_SETAFFINITY_PENDING	- Affinity setting is pending + * IRQD_NO_BALANCING		- Balancing disabled for this IRQ + * IRQD_PER_CPU			- Interrupt is per cpu + * IRQD_AFFINITY_SET		- Interrupt affinity was set + * IRQD_LEVEL			- Interrupt is level triggered + * IRQD_WAKEUP_STATE		- Interrupt is configured for wakeup + *				  from suspend + * IRDQ_MOVE_PCNTXT		- Interrupt can be moved in process + *				  context + */ +enum { +	IRQD_TRIGGER_MASK		= 0xf, +	IRQD_SETAFFINITY_PENDING	= (1 <<  8), +	IRQD_NO_BALANCING		= (1 << 10), +	IRQD_PER_CPU			= (1 << 11), +	IRQD_AFFINITY_SET		= (1 << 12), +	IRQD_LEVEL			= (1 << 13), +	IRQD_WAKEUP_STATE		= (1 << 14), +	IRQD_MOVE_PCNTXT		= (1 << 15), +}; + +static inline bool irqd_is_setaffinity_pending(struct irq_data *d) +{ +	return d->state_use_accessors & IRQD_SETAFFINITY_PENDING; +} + +static inline bool irqd_is_per_cpu(struct irq_data *d) +{ +	return d->state_use_accessors & IRQD_PER_CPU; +} + +static inline bool irqd_can_balance(struct irq_data *d) +{ +	return !(d->state_use_accessors & (IRQD_PER_CPU | IRQD_NO_BALANCING)); +} + +static inline bool irqd_affinity_was_set(struct irq_data *d) +{ +	return d->state_use_accessors & IRQD_AFFINITY_SET; +} + +static inline u32 irqd_get_trigger_type(struct irq_data *d) +{ +	return d->state_use_accessors & IRQD_TRIGGER_MASK; +} + +/* + * Must only be called inside irq_chip.irq_set_type() functions. + */ +static inline void irqd_set_trigger_type(struct irq_data *d, u32 type) +{ +	d->state_use_accessors &= ~IRQD_TRIGGER_MASK; +	d->state_use_accessors |= type & IRQD_TRIGGER_MASK; +} + +static inline bool irqd_is_level_type(struct irq_data *d) +{ +	return d->state_use_accessors & IRQD_LEVEL; +} + +static inline bool irqd_is_wakeup_set(struct irq_data *d) +{ +	return d->state_use_accessors & IRQD_WAKEUP_STATE; +} + +static inline bool irqd_can_move_in_process_context(struct irq_data *d) +{ +	return d->state_use_accessors & IRQD_MOVE_PCNTXT; +} +  /**   * struct irq_chip - hardware interrupt chip descriptor   * @@ -149,6 +270,7 @@ struct irq_data {   * @irq_set_wake:	enable/disable power-management wake-on of an IRQ   * @irq_bus_lock:	function to lock access to slow bus (i2c) chips   * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips + * @flags:		chip specific flags   *   * @release:		release function solely used by UML   */ @@ -195,12 +317,27 @@ struct irq_chip {  	void		(*irq_bus_lock)(struct irq_data *data);  	void		(*irq_bus_sync_unlock)(struct irq_data *data); +	unsigned long	flags; +  	/* Currently used only by UML, might disappear one day.*/  #ifdef CONFIG_IRQ_RELEASE_METHOD  	void		(*release)(unsigned int irq, void *dev_id);  #endif  }; +/* + * irq_chip specific flags + * + * IRQCHIP_SET_TYPE_MASKED:	Mask before calling chip.irq_set_type() + * IRQCHIP_EOI_IF_HANDLED:	Only issue irq_eoi() when irq was handled + * IRQCHIP_MASK_ON_SUSPEND:	Mask non wake irqs in the suspend path + */ +enum { +	IRQCHIP_SET_TYPE_MASKED		= (1 <<  0), +	IRQCHIP_EOI_IF_HANDLED		= (1 <<  1), +	IRQCHIP_MASK_ON_SUSPEND		= (1 <<  2), +}; +  /* This include will go away once we isolated irq_desc usage to core code */  #include <linux/irqdesc.h> @@ -217,7 +354,7 @@ struct irq_chip {  # define ARCH_IRQ_INIT_FLAGS	0  #endif -#define IRQ_DEFAULT_INIT_FLAGS	(IRQ_DISABLED | ARCH_IRQ_INIT_FLAGS) +#define IRQ_DEFAULT_INIT_FLAGS	ARCH_IRQ_INIT_FLAGS  struct irqaction;  extern int setup_irq(unsigned int irq, struct irqaction *new); @@ -228,9 +365,13 @@ extern void remove_irq(unsigned int irq, struct irqaction *act);  #if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ)  void move_native_irq(int irq);  void move_masked_irq(int irq); +void irq_move_irq(struct irq_data *data); +void irq_move_masked_irq(struct irq_data *data);  #else  static inline void move_native_irq(int irq) { }  static inline void move_masked_irq(int irq) { } +static inline void irq_move_irq(struct irq_data *data) { } +static inline void irq_move_masked_irq(struct irq_data *data) { }  #endif  extern int no_irq_affinity; @@ -266,23 +407,23 @@ extern struct irq_chip no_irq_chip;  extern struct irq_chip dummy_irq_chip;  extern void -set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, -			 irq_flow_handler_t handle); -extern void -set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, +irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,  			      irq_flow_handler_t handle, const char *name); +static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip, +					    irq_flow_handler_t handle) +{ +	irq_set_chip_and_handler_name(irq, chip, handle, NULL); +} +  extern void -__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, +__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,  		  const char *name); -/* - * Set a highlevel flow handler for a given IRQ: - */  static inline void -set_irq_handler(unsigned int irq, irq_flow_handler_t handle) +irq_set_handler(unsigned int irq, irq_flow_handler_t handle)  { -	__set_irq_handler(irq, handle, 0, NULL); +	__irq_set_handler(irq, handle, 0, NULL);  }  /* @@ -291,14 +432,11 @@ set_irq_handler(unsigned int irq, irq_flow_handler_t handle)   *  IRQ_NOREQUEST and IRQ_NOPROBE)   */  static inline void -set_irq_chained_handler(unsigned int irq, -			irq_flow_handler_t handle) +irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle)  { -	__set_irq_handler(irq, handle, 1, NULL); +	__irq_set_handler(irq, handle, 1, NULL);  } -extern void set_irq_nested_thread(unsigned int irq, int nest); -  void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set);  static inline void irq_set_status_flags(unsigned int irq, unsigned long set) @@ -311,16 +449,24 @@ static inline void irq_clear_status_flags(unsigned int irq, unsigned long clr)  	irq_modify_status(irq, clr, 0);  } -static inline void set_irq_noprobe(unsigned int irq) +static inline void irq_set_noprobe(unsigned int irq)  {  	irq_modify_status(irq, 0, IRQ_NOPROBE);  } -static inline void set_irq_probe(unsigned int irq) +static inline void irq_set_probe(unsigned int irq)  {  	irq_modify_status(irq, IRQ_NOPROBE, 0);  } +static inline void irq_set_nested_thread(unsigned int irq, bool nest) +{ +	if (nest) +		irq_set_status_flags(irq, IRQ_NESTED_THREAD); +	else +		irq_clear_status_flags(irq, IRQ_NESTED_THREAD); +} +  /* Handle dynamic irq creation and destruction */  extern unsigned int create_irq_nr(unsigned int irq_want, int node);  extern int create_irq(void); @@ -337,14 +483,14 @@ static inline void dynamic_irq_init(unsigned int irq)  }  /* Set/get chip/data for an IRQ: */ -extern int set_irq_chip(unsigned int irq, struct irq_chip *chip); -extern int set_irq_data(unsigned int irq, void *data); -extern int set_irq_chip_data(unsigned int irq, void *data); -extern int set_irq_type(unsigned int irq, unsigned int type); -extern int set_irq_msi(unsigned int irq, struct msi_desc *entry); +extern int irq_set_chip(unsigned int irq, struct irq_chip *chip); +extern int irq_set_handler_data(unsigned int irq, void *data); +extern int irq_set_chip_data(unsigned int irq, void *data); +extern int irq_set_irq_type(unsigned int irq, unsigned int type); +extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry);  extern struct irq_data *irq_get_irq_data(unsigned int irq); -static inline struct irq_chip *get_irq_chip(unsigned int irq) +static inline struct irq_chip *irq_get_chip(unsigned int irq)  {  	struct irq_data *d = irq_get_irq_data(irq);  	return d ? d->chip : NULL; @@ -355,7 +501,7 @@ static inline struct irq_chip *irq_data_get_irq_chip(struct irq_data *d)  	return d->chip;  } -static inline void *get_irq_chip_data(unsigned int irq) +static inline void *irq_get_chip_data(unsigned int irq)  {  	struct irq_data *d = irq_get_irq_data(irq);  	return d ? d->chip_data : NULL; @@ -366,18 +512,18 @@ static inline void *irq_data_get_irq_chip_data(struct irq_data *d)  	return d->chip_data;  } -static inline void *get_irq_data(unsigned int irq) +static inline void *irq_get_handler_data(unsigned int irq)  {  	struct irq_data *d = irq_get_irq_data(irq);  	return d ? d->handler_data : NULL;  } -static inline void *irq_data_get_irq_data(struct irq_data *d) +static inline void *irq_data_get_irq_handler_data(struct irq_data *d)  {  	return d->handler_data;  } -static inline struct msi_desc *get_irq_msi(unsigned int irq) +static inline struct msi_desc *irq_get_msi_desc(unsigned int irq)  {  	struct irq_data *d = irq_get_irq_data(irq);  	return d ? d->msi_desc : NULL; @@ -388,6 +534,89 @@ static inline struct msi_desc *irq_data_get_msi(struct irq_data *d)  	return d->msi_desc;  } +#ifndef CONFIG_GENERIC_HARDIRQS_NO_COMPAT +/* Please do not use: Use the replacement functions instead */ +static inline int set_irq_chip(unsigned int irq, struct irq_chip *chip) +{ +	return irq_set_chip(irq, chip); +} +static inline int set_irq_data(unsigned int irq, void *data) +{ +	return irq_set_handler_data(irq, data); +} +static inline int set_irq_chip_data(unsigned int irq, void *data) +{ +	return irq_set_chip_data(irq, data); +} +static inline int set_irq_type(unsigned int irq, unsigned int type) +{ +	return irq_set_irq_type(irq, type); +} +static inline int set_irq_msi(unsigned int irq, struct msi_desc *entry) +{ +	return irq_set_msi_desc(irq, entry); +} +static inline struct irq_chip *get_irq_chip(unsigned int irq) +{ +	return irq_get_chip(irq); +} +static inline void *get_irq_chip_data(unsigned int irq) +{ +	return irq_get_chip_data(irq); +} +static inline void *get_irq_data(unsigned int irq) +{ +	return irq_get_handler_data(irq); +} +static inline void *irq_data_get_irq_data(struct irq_data *d) +{ +	return irq_data_get_irq_handler_data(d); +} +static inline struct msi_desc *get_irq_msi(unsigned int irq) +{ +	return irq_get_msi_desc(irq); +} +static inline void set_irq_noprobe(unsigned int irq) +{ +	irq_set_noprobe(irq); +} +static inline void set_irq_probe(unsigned int irq) +{ +	irq_set_probe(irq); +} +static inline void set_irq_nested_thread(unsigned int irq, int nest) +{ +	irq_set_nested_thread(irq, nest); +} +static inline void +set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, +			      irq_flow_handler_t handle, const char *name) +{ +	irq_set_chip_and_handler_name(irq, chip, handle, name); +} +static inline void +set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip, +			 irq_flow_handler_t handle) +{ +	irq_set_chip_and_handler(irq, chip, handle); +} +static inline void +__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, +		  const char *name) +{ +	__irq_set_handler(irq, handle, is_chained, name); +} +static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle) +{ +	irq_set_handler(irq, handle); +} +static inline void +set_irq_chained_handler(unsigned int irq, irq_flow_handler_t handle) +{ +	irq_set_chained_handler(irq, handle); +} +#endif +  int irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node);  void irq_free_descs(unsigned int irq, unsigned int cnt);  int irq_reserve_irqs(unsigned int from, unsigned int cnt); | 
