mirror of https://github.com/hak5/openwrt.git
153 lines
4.8 KiB
Diff
153 lines
4.8 KiB
Diff
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(-)
|
|
|
|
--- 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_ms
|
|
.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(stru
|
|
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(stru
|
|
|
|
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(struc
|
|
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 plat
|
|
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);
|