aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/layerscape/patches-4.4/8241-irqchip-ls-scfg-msi-add-MSI-affinity-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/layerscape/patches-4.4/8241-irqchip-ls-scfg-msi-add-MSI-affinity-support.patch')
-rw-r--r--target/linux/layerscape/patches-4.4/8241-irqchip-ls-scfg-msi-add-MSI-affinity-support.patch157
1 files changed, 157 insertions, 0 deletions
diff --git a/target/linux/layerscape/patches-4.4/8241-irqchip-ls-scfg-msi-add-MSI-affinity-support.patch b/target/linux/layerscape/patches-4.4/8241-irqchip-ls-scfg-msi-add-MSI-affinity-support.patch
new file mode 100644
index 0000000000..dbaef7a652
--- /dev/null
+++ b/target/linux/layerscape/patches-4.4/8241-irqchip-ls-scfg-msi-add-MSI-affinity-support.patch
@@ -0,0 +1,157 @@
+From a761ae710d6395af0d8d17a0b4b8f93a816ead46 Mon Sep 17 00:00:00 2001
+From: Minghuan Lian <Minghuan.Lian@nxp.com>
+Date: Tue, 17 Jan 2017 17:32:43 +0800
+Subject: [PATCH 12/13] irqchip/ls-scfg-msi: add MSI affinity support
+
+Cherry-pick patchwork patch.
+
+For LS1046a and LS1043a v1.1, the MSI controller has 4 MSIRs and 4 GIC
+SPI interrupts which can be associated with different Core.
+So we can support affinity to improve the performance.
+The MSI message data is a byte for Layerscape MSI.
+ 7 6 5 4 3 2 1 0
+| - | IBS | SRS |
+SRS bit0-1 is to select a MSIR which is associated with a CPU.
+IBS bit2-6 of ls1046, bit2-4 of ls1043a v1.1 is to select bit of the
+MSIR. With affinity, only bits of MSIR0(srs=0 cpu0) are available.
+All other bits of the MSIR1-3(cpu1-3) are reserved. The MSI hwirq
+always equals bit index of the MSIR0. When changing affinity, MSI
+message data will be appended corresponding SRS then MSI will be
+moved to the corresponding core.
+But in affinity mode, there is only 8 MSI interrupts for a controller
+of LS1043a v1.1. It cannot meet the requirement of the some PCIe
+devices such as 4 ports Ethernet card. In contrast, without affinity,
+all MSIRs can be used for core 0, the MSI interrupts can up to 32.
+So the parameter is added to control affinity mode.
+"lsmsi=no-affinity" will disable affinity and increase MSI
+interrupt number.
+
+Signed-off-by: Minghuan Lian <Minghuan.Lian@nxp.com>
+Signed-off-by: Yangbo Lu <yangbo.lu@nxp.com>
+---
+ drivers/irqchip/irq-ls-scfg-msi.c | 68 ++++++++++++++++++++++++++++++++++++---
+ 1 file changed, 63 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
+index 71a2050..57e3d90 100644
+--- a/drivers/irqchip/irq-ls-scfg-msi.c
++++ b/drivers/irqchip/irq-ls-scfg-msi.c
+@@ -40,6 +40,7 @@ struct ls_scfg_msir {
+ unsigned int gic_irq;
+ unsigned int bit_start;
+ unsigned int bit_end;
++ unsigned int srs; /* Shared interrupt register select */
+ void __iomem *reg;
+ };
+
+@@ -70,6 +71,19 @@ static struct msi_domain_info ls_scfg_msi_domain_info = {
+ .chip = &ls_scfg_msi_irq_chip,
+ };
+
++static int msi_affinity_flag = 1;
++
++static int __init early_parse_ls_scfg_msi(char *p)
++{
++ if (p && strncmp(p, "no-affinity", 11) == 0)
++ msi_affinity_flag = 0;
++ else
++ msi_affinity_flag = 1;
++
++ return 0;
++}
++early_param("lsmsi", early_parse_ls_scfg_msi);
++
+ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
+ {
+ struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data);
+@@ -77,12 +91,36 @@ static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
+ msg->address_hi = upper_32_bits(msi_data->msiir_addr);
+ msg->address_lo = lower_32_bits(msi_data->msiir_addr);
+ msg->data = data->hwirq;
++
++ if (msi_affinity_flag)
++ msg->data |= cpumask_first(data->common->affinity);
+ }
+
+ static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+ {
+- return -EINVAL;
++ struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data);
++ u32 cpu;
++
++ if (!msi_affinity_flag)
++ return -EINVAL;
++
++ if (!force)
++ cpu = cpumask_any_and(mask, cpu_online_mask);
++ else
++ cpu = cpumask_first(mask);
++
++ if (cpu >= msi_data->msir_num)
++ return -EINVAL;
++
++ if (msi_data->msir[cpu].gic_irq <= 0) {
++ pr_warn("cannot bind the irq to cpu%d\n", cpu);
++ return -EINVAL;
++ }
++
++ cpumask_copy(irq_data->common->affinity, mask);
++
++ return IRQ_SET_MASK_OK;
+ }
+
+ static struct irq_chip ls_scfg_msi_parent_chip = {
+@@ -158,7 +196,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
+
+ for_each_set_bit_from(pos, &val, size) {
+ hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
+- msir->index;
++ msir->srs;
+ virq = irq_find_mapping(msi_data->parent, hwirq);
+ if (virq)
+ generic_handle_irq(virq);
+@@ -221,10 +259,19 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
+ ls_scfg_msi_irq_handler,
+ msir);
+
++ if (msi_affinity_flag) {
++ /* Associate MSIR interrupt to the cpu */
++ irq_set_affinity(msir->gic_irq, get_cpu_mask(index));
++ msir->srs = 0; /* This value is determined by the CPU */
++ } else
++ msir->srs = index;
++
+ /* Release the hwirqs corresponding to this MSIR */
+- for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
+- hwirq = i << msi_data->cfg->ibs_shift | msir->index;
+- bitmap_clear(msi_data->used, hwirq, 1);
++ if (!msi_affinity_flag || msir->index == 0) {
++ for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
++ hwirq = i << msi_data->cfg->ibs_shift | msir->index;
++ bitmap_clear(msi_data->used, hwirq, 1);
++ }
+ }
+
+ return 0;
+@@ -321,6 +368,17 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
+ bitmap_set(msi_data->used, 0, msi_data->irqs_num);
+
+ msi_data->msir_num = of_irq_count(pdev->dev.of_node);
++
++ if (msi_affinity_flag) {
++ u32 cpu_num;
++
++ cpu_num = num_possible_cpus();
++ if (msi_data->msir_num >= cpu_num)
++ msi_data->msir_num = cpu_num;
++ else
++ msi_affinity_flag = 0;
++ }
++
+ msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
+ sizeof(*msi_data->msir),
+ GFP_KERNEL);
+--
+2.1.0.27.g96db324
+