Commit 59ee7621 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fixes from Ingo Molnar:
 "Misc irq fixes:

   - two driver fixes
   - a Xen regression fix
   - a nested irq thread crash fix"

* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  irqchip/gicv3-its: Fix mapping of LPIs to collections
  genirq: Prevent resend to interrupts marked IRQ_NESTED_THREAD
  genirq: Revert sparse irq locking around __cpu_up() and move it to x86 for now
  gpio/davinci: Fix race in installing chained irq handler
parents 3a26a5b1 591e5bec
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -992,8 +992,17 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle)

	common_cpu_up(cpu, tidle);

	/*
	 * We have to walk the irq descriptors to setup the vector
	 * space for the cpu which comes online.  Prevent irq
	 * alloc/free across the bringup.
	 */
	irq_lock_sparse();

	err = do_boot_cpu(apicid, cpu, tidle);

	if (err) {
		irq_unlock_sparse();
		pr_err("do_boot_cpu failed(%d) to wakeup CPU#%u\n", err, cpu);
		return -EIO;
	}
@@ -1011,6 +1020,8 @@ int native_cpu_up(unsigned int cpu, struct task_struct *tidle)
		touch_nmi_watchdog();
	}

	irq_unlock_sparse();

	return 0;
}

+2 −4
Original line number Diff line number Diff line
@@ -578,15 +578,13 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
		writel_relaxed(~0, &g->clr_falling);
		writel_relaxed(~0, &g->clr_rising);

		/* set up all irqs in this bank */
		irq_set_chained_handler(bank_irq, gpio_irq_handler);

		/*
		 * Each chip handles 32 gpios, and each irq bank consists of 16
		 * gpio irqs. Pass the irq bank's corresponding controller to
		 * the chained irq handler.
		 */
		irq_set_handler_data(bank_irq, &chips[gpio / 32]);
		irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler,
						 &chips[gpio / 32]);

		binten |= BIT(bank);
	}
+75 −36
Original line number Diff line number Diff line
@@ -75,6 +75,13 @@ struct its_node {

#define ITS_ITT_ALIGN		SZ_256

struct event_lpi_map {
	unsigned long		*lpi_map;
	u16			*col_map;
	irq_hw_number_t		lpi_base;
	int			nr_lpis;
};

/*
 * The ITS view of a device - belongs to an ITS, a collection, owns an
 * interrupt translation table, and a list of interrupts.
@@ -82,11 +89,8 @@ struct its_node {
struct its_device {
	struct list_head	entry;
	struct its_node		*its;
	struct its_collection	*collection;
	struct event_lpi_map	event_map;
	void			*itt;
	unsigned long		*lpi_map;
	irq_hw_number_t		lpi_base;
	int			nr_lpis;
	u32			nr_ites;
	u32			device_id;
};
@@ -99,6 +103,14 @@ static struct rdists *gic_rdists;
#define gic_data_rdist()		(raw_cpu_ptr(gic_rdists->rdist))
#define gic_data_rdist_rd_base()	(gic_data_rdist()->rd_base)

static struct its_collection *dev_event_to_col(struct its_device *its_dev,
					       u32 event)
{
	struct its_node *its = its_dev->its;

	return its->collections + its_dev->event_map.col_map[event];
}

/*
 * ITS command descriptors - parameters to be encoded in a command
 * block.
@@ -134,7 +146,7 @@ struct its_cmd_desc {
		struct {
			struct its_device *dev;
			struct its_collection *col;
			u32 id;
			u32 event_id;
		} its_movi_cmd;

		struct {
@@ -241,7 +253,7 @@ static struct its_collection *its_build_mapd_cmd(struct its_cmd_block *cmd,

	its_fixup_cmd(cmd);

	return desc->its_mapd_cmd.dev->collection;
	return NULL;
}

static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
@@ -260,52 +272,72 @@ static struct its_collection *its_build_mapc_cmd(struct its_cmd_block *cmd,
static struct its_collection *its_build_mapvi_cmd(struct its_cmd_block *cmd,
						  struct its_cmd_desc *desc)
{
	struct its_collection *col;

	col = dev_event_to_col(desc->its_mapvi_cmd.dev,
			       desc->its_mapvi_cmd.event_id);

	its_encode_cmd(cmd, GITS_CMD_MAPVI);
	its_encode_devid(cmd, desc->its_mapvi_cmd.dev->device_id);
	its_encode_event_id(cmd, desc->its_mapvi_cmd.event_id);
	its_encode_phys_id(cmd, desc->its_mapvi_cmd.phys_id);
	its_encode_collection(cmd, desc->its_mapvi_cmd.dev->collection->col_id);
	its_encode_collection(cmd, col->col_id);

	its_fixup_cmd(cmd);

	return desc->its_mapvi_cmd.dev->collection;
	return col;
}

static struct its_collection *its_build_movi_cmd(struct its_cmd_block *cmd,
						 struct its_cmd_desc *desc)
{
	struct its_collection *col;

	col = dev_event_to_col(desc->its_movi_cmd.dev,
			       desc->its_movi_cmd.event_id);

	its_encode_cmd(cmd, GITS_CMD_MOVI);
	its_encode_devid(cmd, desc->its_movi_cmd.dev->device_id);
	its_encode_event_id(cmd, desc->its_movi_cmd.id);
	its_encode_event_id(cmd, desc->its_movi_cmd.event_id);
	its_encode_collection(cmd, desc->its_movi_cmd.col->col_id);

	its_fixup_cmd(cmd);

	return desc->its_movi_cmd.dev->collection;
	return col;
}

static struct its_collection *its_build_discard_cmd(struct its_cmd_block *cmd,
						    struct its_cmd_desc *desc)
{
	struct its_collection *col;

	col = dev_event_to_col(desc->its_discard_cmd.dev,
			       desc->its_discard_cmd.event_id);

	its_encode_cmd(cmd, GITS_CMD_DISCARD);
	its_encode_devid(cmd, desc->its_discard_cmd.dev->device_id);
	its_encode_event_id(cmd, desc->its_discard_cmd.event_id);

	its_fixup_cmd(cmd);

	return desc->its_discard_cmd.dev->collection;
	return col;
}

static struct its_collection *its_build_inv_cmd(struct its_cmd_block *cmd,
						struct its_cmd_desc *desc)
{
	struct its_collection *col;

	col = dev_event_to_col(desc->its_inv_cmd.dev,
			       desc->its_inv_cmd.event_id);

	its_encode_cmd(cmd, GITS_CMD_INV);
	its_encode_devid(cmd, desc->its_inv_cmd.dev->device_id);
	its_encode_event_id(cmd, desc->its_inv_cmd.event_id);

	its_fixup_cmd(cmd);

	return desc->its_inv_cmd.dev->collection;
	return col;
}

static struct its_collection *its_build_invall_cmd(struct its_cmd_block *cmd,
@@ -497,7 +529,7 @@ static void its_send_movi(struct its_device *dev,

	desc.its_movi_cmd.dev = dev;
	desc.its_movi_cmd.col = col;
	desc.its_movi_cmd.id = id;
	desc.its_movi_cmd.event_id = id;

	its_send_single_command(dev->its, its_build_movi_cmd, &desc);
}
@@ -528,7 +560,7 @@ static void its_send_invall(struct its_node *its, struct its_collection *col)
static inline u32 its_get_event_id(struct irq_data *d)
{
	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
	return d->hwirq - its_dev->lpi_base;
	return d->hwirq - its_dev->event_map.lpi_base;
}

static void lpi_set_config(struct irq_data *d, bool enable)
@@ -583,7 +615,7 @@ static int its_set_affinity(struct irq_data *d, const struct cpumask *mask_val,

	target_col = &its_dev->its->collections[cpu];
	its_send_movi(its_dev, target_col, id);
	its_dev->collection = target_col;
	its_dev->event_map.col_map[id] = cpu;

	return IRQ_SET_MASK_OK_DONE;
}
@@ -713,8 +745,10 @@ out:
	return bitmap;
}

static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)
static void its_lpi_free(struct event_lpi_map *map)
{
	int base = map->lpi_base;
	int nr_ids = map->nr_lpis;
	int lpi;

	spin_lock(&lpi_lock);
@@ -731,7 +765,8 @@ static void its_lpi_free(unsigned long *bitmap, int base, int nr_ids)

	spin_unlock(&lpi_lock);

	kfree(bitmap);
	kfree(map->lpi_map);
	kfree(map->col_map);
}

/*
@@ -1099,11 +1134,11 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
	struct its_device *dev;
	unsigned long *lpi_map;
	unsigned long flags;
	u16 *col_map = NULL;
	void *itt;
	int lpi_base;
	int nr_lpis;
	int nr_ites;
	int cpu;
	int sz;

	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1117,20 +1152,24 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
	sz = max(sz, ITS_ITT_ALIGN) + ITS_ITT_ALIGN - 1;
	itt = kzalloc(sz, GFP_KERNEL);
	lpi_map = its_lpi_alloc_chunks(nvecs, &lpi_base, &nr_lpis);
	if (lpi_map)
		col_map = kzalloc(sizeof(*col_map) * nr_lpis, GFP_KERNEL);

	if (!dev || !itt || !lpi_map) {
	if (!dev || !itt || !lpi_map || !col_map) {
		kfree(dev);
		kfree(itt);
		kfree(lpi_map);
		kfree(col_map);
		return NULL;
	}

	dev->its = its;
	dev->itt = itt;
	dev->nr_ites = nr_ites;
	dev->lpi_map = lpi_map;
	dev->lpi_base = lpi_base;
	dev->nr_lpis = nr_lpis;
	dev->event_map.lpi_map = lpi_map;
	dev->event_map.col_map = col_map;
	dev->event_map.lpi_base = lpi_base;
	dev->event_map.nr_lpis = nr_lpis;
	dev->device_id = dev_id;
	INIT_LIST_HEAD(&dev->entry);

@@ -1138,10 +1177,6 @@ static struct its_device *its_create_device(struct its_node *its, u32 dev_id,
	list_add(&dev->entry, &its->its_device_list);
	raw_spin_unlock_irqrestore(&its->lock, flags);

	/* Bind the device to the first possible CPU */
	cpu = cpumask_first(cpu_online_mask);
	dev->collection = &its->collections[cpu];

	/* Map device to its ITT */
	its_send_mapd(dev, 1);

@@ -1163,12 +1198,13 @@ static int its_alloc_device_irq(struct its_device *dev, irq_hw_number_t *hwirq)
{
	int idx;

	idx = find_first_zero_bit(dev->lpi_map, dev->nr_lpis);
	if (idx == dev->nr_lpis)
	idx = find_first_zero_bit(dev->event_map.lpi_map,
				  dev->event_map.nr_lpis);
	if (idx == dev->event_map.nr_lpis)
		return -ENOSPC;

	*hwirq = dev->lpi_base + idx;
	set_bit(idx, dev->lpi_map);
	*hwirq = dev->event_map.lpi_base + idx;
	set_bit(idx, dev->event_map.lpi_map);

	return 0;
}
@@ -1288,7 +1324,8 @@ static int its_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
		irq_domain_set_hwirq_and_chip(domain, virq + i,
					      hwirq, &its_irq_chip, its_dev);
		dev_dbg(info->scratchpad[1].ptr, "ID:%d pID:%d vID:%d\n",
			(int)(hwirq - its_dev->lpi_base), (int)hwirq, virq + i);
			(int)(hwirq - its_dev->event_map.lpi_base),
			(int)hwirq, virq + i);
	}

	return 0;
@@ -1300,6 +1337,9 @@ static void its_irq_domain_activate(struct irq_domain *domain,
	struct its_device *its_dev = irq_data_get_irq_chip_data(d);
	u32 event = its_get_event_id(d);

	/* Bind the LPI to the first possible CPU */
	its_dev->event_map.col_map[event] = cpumask_first(cpu_online_mask);

	/* Map the GIC IRQ and event to the device */
	its_send_mapvi(its_dev, d->hwirq, event);
}
@@ -1327,17 +1367,16 @@ static void its_irq_domain_free(struct irq_domain *domain, unsigned int virq,
		u32 event = its_get_event_id(data);

		/* Mark interrupt index as unused */
		clear_bit(event, its_dev->lpi_map);
		clear_bit(event, its_dev->event_map.lpi_map);

		/* Nuke the entry in the domain */
		irq_domain_reset_irq_data(data);
	}

	/* If all interrupts have been freed, start mopping the floor */
	if (bitmap_empty(its_dev->lpi_map, its_dev->nr_lpis)) {
		its_lpi_free(its_dev->lpi_map,
			     its_dev->lpi_base,
			     its_dev->nr_lpis);
	if (bitmap_empty(its_dev->event_map.lpi_map,
			 its_dev->event_map.nr_lpis)) {
		its_lpi_free(&its_dev->event_map);

		/* Unmap device/itt */
		its_send_mapd(its_dev, 0);
+0 −9
Original line number Diff line number Diff line
@@ -527,18 +527,9 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen)
		goto out_notify;
	}

	/*
	 * Some architectures have to walk the irq descriptors to
	 * setup the vector space for the cpu which comes online.
	 * Prevent irq alloc/free across the bringup.
	 */
	irq_lock_sparse();

	/* Arch-specific enabling code. */
	ret = __cpu_up(cpu, idle);

	irq_unlock_sparse();

	if (ret != 0)
		goto out_notify;
	BUG_ON(!cpu_online(cpu));
+13 −5
Original line number Diff line number Diff line
@@ -75,13 +75,21 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)
		    !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
#ifdef CONFIG_HARDIRQS_SW_RESEND
			/*
			 * If the interrupt has a parent irq and runs
			 * in the thread context of the parent irq,
			 * retrigger the parent.
			 * If the interrupt is running in the thread
			 * context of the parent irq we need to be
			 * careful, because we cannot trigger it
			 * directly.
			 */
			if (desc->parent_irq &&
			    irq_settings_is_nested_thread(desc))
			if (irq_settings_is_nested_thread(desc)) {
				/*
				 * If the parent_irq is valid, we
				 * retrigger the parent, otherwise we
				 * do nothing.
				 */
				if (!desc->parent_irq)
					return;
				irq = desc->parent_irq;
			}
			/* Set it pending and activate the softirq: */
			set_bit(irq, irqs_resend);
			tasklet_schedule(&resend_tasklet);