| Subject: random: Make it work on rt | 
 | From: Thomas Gleixner <tglx@linutronix.de> | 
 | Date: Tue, 21 Aug 2012 20:38:50 +0200 | 
 |  | 
 | Delegate the random insertion to the forced threaded interrupt | 
 | handler. Store the return IP of the hard interrupt handler in the irq | 
 | descriptor and feed it into the random generator as a source of | 
 | entropy. | 
 |  | 
 | Signed-off-by: Thomas Gleixner <tglx@linutronix.de> | 
 | Cc: stable-rt@vger.kernel.org | 
 | --- | 
 |  drivers/char/random.c   |   10 ++++++---- | 
 |  include/linux/irqdesc.h |    1 + | 
 |  include/linux/random.h  |    2 +- | 
 |  kernel/irq/handle.c     |    8 +++++++- | 
 |  kernel/irq/manage.c     |    6 ++++++ | 
 |  5 files changed, 21 insertions(+), 6 deletions(-) | 
 |  | 
 | Index: linux-stable/drivers/char/random.c | 
 | =================================================================== | 
 | --- linux-stable.orig/drivers/char/random.c | 
 | +++ linux-stable/drivers/char/random.c | 
 | @@ -745,18 +745,16 @@ EXPORT_SYMBOL_GPL(add_input_randomness); | 
 |   | 
 |  static DEFINE_PER_CPU(struct fast_pool, irq_randomness); | 
 |   | 
 | -void add_interrupt_randomness(int irq, int irq_flags) | 
 | +void add_interrupt_randomness(int irq, int irq_flags, __u64 ip) | 
 |  { | 
 |  	struct entropy_store	*r; | 
 |  	struct fast_pool	*fast_pool = &__get_cpu_var(irq_randomness); | 
 | -	struct pt_regs		*regs = get_irq_regs(); | 
 |  	unsigned long		now = jiffies; | 
 |  	__u32			input[4], cycles = get_cycles(); | 
 |   | 
 |  	input[0] = cycles ^ jiffies; | 
 |  	input[1] = irq; | 
 | -	if (regs) { | 
 | -		__u64 ip = instruction_pointer(regs); | 
 | +	if (ip) { | 
 |  		input[2] = ip; | 
 |  		input[3] = ip >> 32; | 
 |  	} | 
 | @@ -770,7 +768,11 @@ void add_interrupt_randomness(int irq, i | 
 |  	fast_pool->last = now; | 
 |   | 
 |  	r = nonblocking_pool.initialized ? &input_pool : &nonblocking_pool; | 
 | +#ifndef CONFIG_PREEMPT_RT_FULL | 
 |  	__mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL); | 
 | +#else | 
 | +	mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool), NULL); | 
 | +#endif | 
 |  	/* | 
 |  	 * If we don't have a valid cycle counter, and we see | 
 |  	 * back-to-back timer interrupts, then skip giving credit for | 
 | Index: linux-stable/include/linux/irqdesc.h | 
 | =================================================================== | 
 | --- linux-stable.orig/include/linux/irqdesc.h | 
 | +++ linux-stable/include/linux/irqdesc.h | 
 | @@ -52,6 +52,7 @@ struct irq_desc { | 
 |  	unsigned int		irq_count;	/* For detecting broken IRQs */ | 
 |  	unsigned long		last_unhandled;	/* Aging timer for unhandled count */ | 
 |  	unsigned int		irqs_unhandled; | 
 | +	u64			random_ip; | 
 |  	raw_spinlock_t		lock; | 
 |  	struct cpumask		*percpu_enabled; | 
 |  #ifdef CONFIG_SMP | 
 | Index: linux-stable/include/linux/random.h | 
 | =================================================================== | 
 | --- linux-stable.orig/include/linux/random.h | 
 | +++ linux-stable/include/linux/random.h | 
 | @@ -51,7 +51,7 @@ struct rnd_state { | 
 |  extern void add_device_randomness(const void *, unsigned int); | 
 |  extern void add_input_randomness(unsigned int type, unsigned int code, | 
 |  				 unsigned int value); | 
 | -extern void add_interrupt_randomness(int irq, int irq_flags); | 
 | +extern void add_interrupt_randomness(int irq, int irq_flags, __u64 ip); | 
 |   | 
 |  extern void get_random_bytes(void *buf, int nbytes); | 
 |  extern void get_random_bytes_arch(void *buf, int nbytes); | 
 | Index: linux-stable/kernel/irq/handle.c | 
 | =================================================================== | 
 | --- linux-stable.orig/kernel/irq/handle.c | 
 | +++ linux-stable/kernel/irq/handle.c | 
 | @@ -132,6 +132,8 @@ static void irq_wake_thread(struct irq_d | 
 |  irqreturn_t | 
 |  handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) | 
 |  { | 
 | +	struct pt_regs *regs = get_irq_regs(); | 
 | +	u64 ip = regs ? instruction_pointer(regs) : 0; | 
 |  	irqreturn_t retval = IRQ_NONE; | 
 |  	unsigned int flags = 0, irq = desc->irq_data.irq; | 
 |   | 
 | @@ -172,7 +174,11 @@ handle_irq_event_percpu(struct irq_desc  | 
 |  		action = action->next; | 
 |  	} while (action); | 
 |   | 
 | -	add_interrupt_randomness(irq, flags); | 
 | +#ifndef CONFIG_PREEMPT_RT_FULL | 
 | +	add_interrupt_randomness(irq, flags, ip); | 
 | +#else | 
 | +	desc->random_ip = ip; | 
 | +#endif | 
 |   | 
 |  	if (!noirqdebug) | 
 |  		note_interrupt(irq, desc, retval); | 
 | Index: linux-stable/kernel/irq/manage.c | 
 | =================================================================== | 
 | --- linux-stable.orig/kernel/irq/manage.c | 
 | +++ linux-stable/kernel/irq/manage.c | 
 | @@ -852,6 +852,12 @@ static int irq_thread(void *data) | 
 |  		if (!noirqdebug) | 
 |  			note_interrupt(action->irq, desc, action_ret); | 
 |   | 
 | +#ifdef CONFIG_PREEMPT_RT_FULL | 
 | +		migrate_disable(); | 
 | +		add_interrupt_randomness(action->irq, 0, | 
 | +					 desc->random_ip ^ (u64) action); | 
 | +		migrate_enable(); | 
 | +#endif | 
 |  		wake_threads_waitq(desc); | 
 |  	} | 
 |   |