irq_desc_t 型

掘り下げていってるんですが、まだまだ穴は深いんだろうな。(当たり前
include/linux/irq.h によると

typedef struct irq_desc {
	hw_irq_controller *handler;
	void *handler_data;
	struct irqaction *action;	/* IRQ action list */
	unsigned int status;		/* IRQ status */
	unsigned int depth;		/* nested irq disables */
	unsigned int irq_count;		/* For detecting broken interrupts */
	unsigned int irqs_unhandled;
	spinlock_t lock;
} ____cacheline_aligned irq_desc_t;

て感じで定義されている。

メンバの用途、意味合い等は追いかけながら見ていきたい。気になるのは以下のメンバ。

  • handler (hw_irq_controller 型)
  • action (struct irqaction * 型)
  • lock (spinlock_t 型)

探してみる。まず hw_irq_controller 型は M-. したら include/linux/irq.h が開いた。同じファイルやっさ。

struct hw_interrupt_type {
	const char * typename;
	unsigned int (*startup)(unsigned int irq);
	void (*shutdown)(unsigned int irq);
	void (*enable)(unsigned int irq);
	void (*disable)(unsigned int irq);
	void (*ack)(unsigned int irq);
	void (*end)(unsigned int irq);
	void (*set_affinity)(unsigned int irq, cpumask_t dest);
};

typedef struct hw_interrupt_type  hw_irq_controller;

メンバはほとんど関数ポインタになっている。メンバの用途、意味合いは同様に別途調査とゆー事で。

次、struct irqaction 型は include/linux/interrupt.h にて定義。

struct irqaction {
	irqreturn_t (*handler)(int, void *, struct pt_regs *);
	unsigned long flags;
	cpumask_t mask;
	const char *name;
	void *dev_id;
	struct irqaction *next;
	int irq;
	struct proc_dir_entry *dir;
};

struct irqaction *next ってメンバがあるんでリンクリストだな、と。いくつか意味不明なデータ型あり。

  • irqreturn_t 型
  • cpumask_t 型
  • struct proc_dir_entry 型

ちなみに irqreturn_t 型は直上にて typedef されている。

typedef int irqreturn_t;

cpumask_t 型。
include/linux/cpumask.h にて

typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t;

な記述あり。DECLARE_BITMAP は include/linux/types.h にて

#define BITS_TO_LONGS(bits) \
	(((bits)+BITS_PER_LONG-1)/BITS_PER_LONG)
#define DECLARE_BITMAP(name,bits) \
	unsigned long name[BITS_TO_LONGS(bits)]

こんなマクロがあった。NR_CPUS は CPU の数と勝手読みして、ユニ・プロセッサの場合には以下のようなカンジで展開されるはず。

typedef struct {
    unsigned long bits[1]; 
} cpumask_t;

おそらくはビットマップなんで 33 以上 CPU が無い限りは long 一発でなんとなるんだろう、と勝手読み。(勝手読みが多すぎゃしないッスか?

次。struct proc_dir_entry 型なんですが、これについては必要がある時に中身を見ます。ちなみにありかは include/linux/proc_fs.h です。推測ですが、proc ファイルシステムのディレクトリエントリな構造体かと。

最後の spinlock_t 型は include/linux/spinlock.h に。
がしかし、CONFIG_DEBUG_SPINLOCK ってナニな人向けなカーネルコンフィグレーションなのかな。2.4 時代からあるのはこっちみたい。

/*
 * gcc versions before ~2.95 have a nasty bug with empty initializers.
 */
#if (__GNUC__ > 2)
  typedef struct { } spinlock_t;
  #define SPIN_LOCK_UNLOCKED (spinlock_t) { }
#else
  typedef struct { int gcc_is_buggy; } spinlock_t;
  #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 }
#endif

これ、凄いな。sizeof(spinlock_t) は 0 になります。0 バイトの変数か。でも SPIN_LOCK_UNLOCKED でない状態ってどうやるんでしょ。とりあえずこれも保留。

で、kernel/irq/handle.c で定義されておる irq_desc はカーネルがロードされた時点で領域が確保されて初期化される、と。

irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = {
	[0 ... NR_IRQS-1] = {
		.status = IRQ_DISABLED,
		.handler = &no_irq_type,
		.lock = SPIN_LOCK_UNLOCKED
	}
};

メンバとその状態はロードされた時点で以下??

  • hw_irq_controller * 型の handler

&no_irq_type が代入されている

  • void * (汎用ポインタ) 型の handler_data

NULL

  • struct irqaction * 型の action

NULL

  • unsigned int 型の status

IRQ_DISABLED

  • unsigned int 型の depth
  • unsigned int 型の irq_count
  • unsigned int 型の irqs_unhandled
  • spinlock_t 型の lock

SPIN_LOCK_UNLOCKED

最後に、IRQ_DISABLED 関連と no_irq_type 関連についてトレース。

include/linux/irq.h にて定義。コメントには IRQ line status. とあり。

#define IRQ_INPROGRESS	1	/* IRQ handler active - do not enter! */
#define IRQ_DISABLED	2	/* IRQ disabled - do not enter! */
#define IRQ_PENDING	4	/* IRQ pending - replay on enable */
#define IRQ_REPLAY	8	/* IRQ has been replayed but not acked yet */
#define IRQ_AUTODETECT	16	/* IRQ is being autodetected */
#define IRQ_WAITING	32	/* IRQ not yet seen - for autodetection */
#define IRQ_LEVEL	64	/* IRQ level triggered */
#define IRQ_MASKED	128	/* IRQ masked - shouldn't be seen again */
#define IRQ_PER_CPU	256	/* IRQ is per CPU */

kernel/irq/handle.c にて定義。

/*
 * Generic 'no controller' code
 */
static void end_none(unsigned int irq) { }
static void enable_none(unsigned int irq) { }
static void disable_none(unsigned int irq) { }
static void shutdown_none(unsigned int irq) { }
static unsigned int startup_none(unsigned int irq) { return 0; }

static void ack_none(unsigned int irq)
{
	/*
	 * 'what should we do if we get a hw irq event on an illegal vector'.
	 * each architecture has to answer this themself.
	 */
	ack_bad_irq(irq);
}

struct hw_interrupt_type no_irq_type = {
	.typename = 	"none",
	.startup = 	startup_none,
	.shutdown = 	shutdown_none,
	.enable = 	enable_none,
	.disable = 	disable_none,
	.ack = 		ack_none,
	.end = 		end_none,
	.set_affinity = NULL
};

何もナシ。というのがハッキリしてて気持ち良し。
関数の型、引数の型が同一なのに名前を変えているのがあるが、何か意味があんのかなぁ。

てか、irq_desc 配列って、「いつ、どこで」本当の意味での初期設定がなされるのでしょうね。とりあえず次のエントリ以降で init_IRQ() に戻ってみたいと。(irq_desc 配列への登録はデバイスドライバが行なっている模様。amazon:Linux カーネル解析入門にて「ネットワーク・ドライバを読む」などという章がありますんで、そこらへんで出てくるのかな)