Commit ff6a1798 authored by Anton Ivanov's avatar Anton Ivanov Committed by Richard Weinberger
Browse files

Epoll based IRQ controller



1. Removes the need to walk the IRQ/Device list to determine
who triggered the IRQ.
2. Improves scalability (up to several times performance
improvement for cases with 10s of devices).
3. Improves UML baseline IO performance for one disk + one NIC
use case by up to 10%.
4. Introduces write poll triggered IRQs.
5. Prerequisite for introducing high performance mmesg family
of functions in network IO.
6. Fixes RNG shutdown which was leaking a file descriptor

Signed-off-by: default avatarAnton Ivanov <anton.ivanov@cambridgegreys.com>
Signed-off-by: default avatarRichard Weinberger <richard@nod.at>
parent 4d1a535b
Loading
Loading
Loading
Loading
+8 −45
Original line number Diff line number Diff line
@@ -171,56 +171,19 @@ int enable_chan(struct line *line)
	return err;
}

/* Items are added in IRQ context, when free_irq can't be called, and
 * removed in process context, when it can.
 * This handles interrupt sources which disappear, and which need to
 * be permanently disabled.  This is discovered in IRQ context, but
 * the freeing of the IRQ must be done later.
 */
static DEFINE_SPINLOCK(irqs_to_free_lock);
static LIST_HEAD(irqs_to_free);

void free_irqs(void)
{
	struct chan *chan;
	LIST_HEAD(list);
	struct list_head *ele;
	unsigned long flags;

	spin_lock_irqsave(&irqs_to_free_lock, flags);
	list_splice_init(&irqs_to_free, &list);
	spin_unlock_irqrestore(&irqs_to_free_lock, flags);

	list_for_each(ele, &list) {
		chan = list_entry(ele, struct chan, free_list);

		if (chan->input && chan->enabled)
			um_free_irq(chan->line->driver->read_irq, chan);
		if (chan->output && chan->enabled)
			um_free_irq(chan->line->driver->write_irq, chan);
		chan->enabled = 0;
	}
}

static void close_one_chan(struct chan *chan, int delay_free_irq)
{
	unsigned long flags;

	if (!chan->opened)
		return;

	if (delay_free_irq) {
		spin_lock_irqsave(&irqs_to_free_lock, flags);
		list_add(&chan->free_list, &irqs_to_free);
		spin_unlock_irqrestore(&irqs_to_free_lock, flags);
	}
	else {
    /* we can safely call free now - it will be marked
     *  as free and freed once the IRQ stopped processing
     */
	if (chan->input && chan->enabled)
		um_free_irq(chan->line->driver->read_irq, chan);
	if (chan->output && chan->enabled)
		um_free_irq(chan->line->driver->write_irq, chan);
	chan->enabled = 0;
	}
	if (chan->ops->close != NULL)
		(*chan->ops->close)(chan->fd, chan->data);

+1 −1
Original line number Diff line number Diff line
@@ -284,7 +284,7 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
	if (err)
		return err;
	if (output)
		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
		err = um_request_irq(driver->write_irq, fd, IRQ_NONE,
				     line_write_interrupt, IRQF_SHARED,
				     driver->write_irq_name, data);
	return err;
+10 −1
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <init.h>
#include <irq_kern.h>
#include <os.h>

@@ -154,6 +155,13 @@ err_out_cleanup_hw:
/*
 * rng_cleanup - shutdown RNG module
 */

static void cleanup(void)
{
	free_irq_by_fd(random_fd);
	os_close_file(random_fd);
}

static void __exit rng_cleanup(void)
{
	os_close_file(random_fd);
@@ -162,6 +170,7 @@ static void __exit rng_cleanup (void)

module_init (rng_init);
module_exit (rng_cleanup);
__uml_exitcall(cleanup);

MODULE_DESCRIPTION("UML Host Random Number Generator (RNG) driver");
MODULE_LICENSE("GPL");
+2 −2
Original line number Diff line number Diff line
@@ -1587,11 +1587,11 @@ int io_thread(void *arg)

		do {
			res = os_write_file(kernel_fd, ((char *) io_req_buffer) + written, n);
			if (res > 0) {
			if (res >= 0) {
				written += res;
			} else {
				if (res != -EAGAIN) {
					printk("io_thread - read failed, fd = %d, "
					printk("io_thread - write failed, fd = %d, "
					       "err = %d\n", kernel_fd, -n);
				}
			}
+10 −2
Original line number Diff line number Diff line
@@ -7,6 +7,7 @@
#define __IRQ_USER_H__

#include <sysdep/ptrace.h>
#include <stdbool.h>

struct irq_fd {
	struct irq_fd *next;
@@ -15,10 +16,17 @@ struct irq_fd {
	int type;
	int irq;
	int events;
	int current_events;
	bool active;
	bool pending;
	bool purge;
};

enum { IRQ_READ, IRQ_WRITE };
#define IRQ_READ  0
#define IRQ_WRITE 1
#define IRQ_NONE 2
#define MAX_IRQ_TYPE (IRQ_NONE + 1)



struct siginfo;
extern void sigio_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs);
Loading