Patch "irqchip/gicv3-its: Fix mapping of LPIs to collections" has been added to the 4.1-stable tree
This is a note to let you know that I've just added the patch titled
irqchip/gicv3-its: Fix mapping of LPIs to collections
to the 4.1-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
irqchip-gicv3-its-fix-mapping-of-lpis-to-collections.patch
and it can be found in the queue-4.1 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
591e5bec13f15feb13fc445b6c9c59954711c4acMon Sep 17 00:00:00 2001
From: Marc Zyngier <[email protected]>
Date: Fri, 17 Jul 2015 10:46:42 +0100
Subject: irqchip/gicv3-its: Fix mapping of LPIs to collections
From: Marc Zyngier <[email protected]>
commit 591e5bec13f15feb13fc445b6c9c59954711c4ac upstream.
The GICv3 ITS architecture allows a given [DevID, EventID] pair to be translated to a [LPI, Collection] pair, where DevID is the device writing the MSI, EventID is the payload being written, LPI is the actual interrupt number, and Collection is roughly equivalent to a target CPU.
Each LPI can be mapped to a separate collection, but the ITS driver insists on maintaining the collection on a device basis, instead of doing it on a per interrupt basis.
This is obviously flawed, and this patch fixes it by adding a per interrupt index that indicates which collection number is in use.
--- drivers/irqchip/irq-gic-v3-its.c | 111 ++++++++++++++++++++++++++------------- 1 file changed, 75 insertions(+), 36 deletions(-)
drivers/irqchip/irq-gic-v3-its.c +75 -36
@@ -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_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_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_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_nstatic 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_d 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 *spin_unlock (&lpi_lock); -kfree (bitmap); +kfree (map->lpi_map); +kfree (map->col_map); }/*
@@ -1099,11 +1134,11 @@ static struct its_device *its_create_devstruct 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_dev 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_devlist_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 i {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 iirq_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(strustruct 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 iu32 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 );
Patches currently in stable-queue which might be from marc.zyngier at arm.com are
queue-4.1/irqchip-gicv3-its-fix-mapping-of-lpis-to-collections.patch