aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMinghuan Lian <Minghuan.Lian@nxp.com>2017-07-05 02:59:03 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2017-08-31 11:19:48 -0400
commitae3efabfadea92a7300f57792ebeb24b5d18469f (patch)
tree9176bdb34002cd91b6a929df97e91c7ff9b534eb
parentfd100dab63ef634e1e0e8b5d9d6d4ba7df9be93f (diff)
irqchip/ls-scfg-msi: Add MSI affinity support
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: Hou Zhiqiang <Zhiqiang.Hou@nxp.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--drivers/irqchip/irq-ls-scfg-msi.c68
1 files changed, 63 insertions, 5 deletions
diff --git a/drivers/irqchip/irq-ls-scfg-msi.c b/drivers/irqchip/irq-ls-scfg-msi.c
index 8d57a599c0fb..119f4ef0d421 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 {
40 unsigned int gic_irq; 40 unsigned int gic_irq;
41 unsigned int bit_start; 41 unsigned int bit_start;
42 unsigned int bit_end; 42 unsigned int bit_end;
43 unsigned int srs; /* Shared interrupt register select */
43 void __iomem *reg; 44 void __iomem *reg;
44}; 45};
45 46
@@ -70,6 +71,19 @@ static struct msi_domain_info ls_scfg_msi_domain_info = {
70 .chip = &ls_scfg_msi_irq_chip, 71 .chip = &ls_scfg_msi_irq_chip,
71}; 72};
72 73
74static int msi_affinity_flag = 1;
75
76static int __init early_parse_ls_scfg_msi(char *p)
77{
78 if (p && strncmp(p, "no-affinity", 11) == 0)
79 msi_affinity_flag = 0;
80 else
81 msi_affinity_flag = 1;
82
83 return 0;
84}
85early_param("lsmsi", early_parse_ls_scfg_msi);
86
73static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg) 87static void ls_scfg_msi_compose_msg(struct irq_data *data, struct msi_msg *msg)
74{ 88{
75 struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(data); 89 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)
77 msg->address_hi = upper_32_bits(msi_data->msiir_addr); 91 msg->address_hi = upper_32_bits(msi_data->msiir_addr);
78 msg->address_lo = lower_32_bits(msi_data->msiir_addr); 92 msg->address_lo = lower_32_bits(msi_data->msiir_addr);
79 msg->data = data->hwirq; 93 msg->data = data->hwirq;
94
95 if (msi_affinity_flag)
96 msg->data |= cpumask_first(data->common->affinity);
80} 97}
81 98
82static int ls_scfg_msi_set_affinity(struct irq_data *irq_data, 99static int ls_scfg_msi_set_affinity(struct irq_data *irq_data,
83 const struct cpumask *mask, bool force) 100 const struct cpumask *mask, bool force)
84{ 101{
85 return -EINVAL; 102 struct ls_scfg_msi *msi_data = irq_data_get_irq_chip_data(irq_data);
103 u32 cpu;
104
105 if (!msi_affinity_flag)
106 return -EINVAL;
107
108 if (!force)
109 cpu = cpumask_any_and(mask, cpu_online_mask);
110 else
111 cpu = cpumask_first(mask);
112
113 if (cpu >= msi_data->msir_num)
114 return -EINVAL;
115
116 if (msi_data->msir[cpu].gic_irq <= 0) {
117 pr_warn("cannot bind the irq to cpu%d\n", cpu);
118 return -EINVAL;
119 }
120
121 cpumask_copy(irq_data->common->affinity, mask);
122
123 return IRQ_SET_MASK_OK;
86} 124}
87 125
88static struct irq_chip ls_scfg_msi_parent_chip = { 126static struct irq_chip ls_scfg_msi_parent_chip = {
@@ -158,7 +196,7 @@ static void ls_scfg_msi_irq_handler(struct irq_desc *desc)
158 196
159 for_each_set_bit_from(pos, &val, size) { 197 for_each_set_bit_from(pos, &val, size) {
160 hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) | 198 hwirq = ((msir->bit_end - pos) << msi_data->cfg->ibs_shift) |
161 msir->index; 199 msir->srs;
162 virq = irq_find_mapping(msi_data->parent, hwirq); 200 virq = irq_find_mapping(msi_data->parent, hwirq);
163 if (virq) 201 if (virq)
164 generic_handle_irq(virq); 202 generic_handle_irq(virq);
@@ -221,10 +259,19 @@ static int ls_scfg_msi_setup_hwirq(struct ls_scfg_msi *msi_data, int index)
221 ls_scfg_msi_irq_handler, 259 ls_scfg_msi_irq_handler,
222 msir); 260 msir);
223 261
262 if (msi_affinity_flag) {
263 /* Associate MSIR interrupt to the cpu */
264 irq_set_affinity(msir->gic_irq, get_cpu_mask(index));
265 msir->srs = 0; /* This value is determined by the CPU */
266 } else
267 msir->srs = index;
268
224 /* Release the hwirqs corresponding to this MSIR */ 269 /* Release the hwirqs corresponding to this MSIR */
225 for (i = 0; i < msi_data->cfg->msir_irqs; i++) { 270 if (!msi_affinity_flag || msir->index == 0) {
226 hwirq = i << msi_data->cfg->ibs_shift | msir->index; 271 for (i = 0; i < msi_data->cfg->msir_irqs; i++) {
227 bitmap_clear(msi_data->used, hwirq, 1); 272 hwirq = i << msi_data->cfg->ibs_shift | msir->index;
273 bitmap_clear(msi_data->used, hwirq, 1);
274 }
228 } 275 }
229 276
230 return 0; 277 return 0;
@@ -320,6 +367,17 @@ static int ls_scfg_msi_probe(struct platform_device *pdev)
320 bitmap_set(msi_data->used, 0, msi_data->irqs_num); 367 bitmap_set(msi_data->used, 0, msi_data->irqs_num);
321 368
322 msi_data->msir_num = of_irq_count(pdev->dev.of_node); 369 msi_data->msir_num = of_irq_count(pdev->dev.of_node);
370
371 if (msi_affinity_flag) {
372 u32 cpu_num;
373
374 cpu_num = num_possible_cpus();
375 if (msi_data->msir_num >= cpu_num)
376 msi_data->msir_num = cpu_num;
377 else
378 msi_affinity_flag = 0;
379 }
380
323 msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num, 381 msi_data->msir = devm_kcalloc(&pdev->dev, msi_data->msir_num,
324 sizeof(*msi_data->msir), 382 sizeof(*msi_data->msir),
325 GFP_KERNEL); 383 GFP_KERNEL);