aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPratyush Anand <pratyush.anand@st.com>2013-10-09 08:32:12 -0400
committerBjorn Helgaas <bhelgaas@google.com>2013-10-09 11:14:23 -0400
commit904d0e7889933fb48d921c998fd1cabb3a9d6635 (patch)
tree71cddd777f8e69fa16098fc8855174eaf6397809
parent73e408508bf6c76d8dc06f044f0e4703a1e27f14 (diff)
PCI: designware: Add irq_create_mapping()
Without irq_create_mapping(), the correct IRQ number cannot be provided. In this case, it makes problems such as NULL dereference. Thus, irq_create_mapping() should be added for MSI. Suggested-by: Kishon Vijay Abraham I <kishon@ti.com> Signed-off-by: Pratyush Anand <pratyush.anand@st.com> Signed-off-by: Jingoo Han <jg1.han@samsung.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/host/pcie-designware.c25
-rw-r--r--drivers/pci/host/pcie-designware.h2
2 files changed, 14 insertions, 13 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index a2e69afabe6f..1e1fea4d959b 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -157,7 +157,7 @@ static struct irq_chip dw_msi_irq_chip = {
157void dw_handle_msi_irq(struct pcie_port *pp) 157void dw_handle_msi_irq(struct pcie_port *pp)
158{ 158{
159 unsigned long val; 159 unsigned long val;
160 int i, pos; 160 int i, pos, irq;
161 161
162 for (i = 0; i < MAX_MSI_CTRLS; i++) { 162 for (i = 0; i < MAX_MSI_CTRLS; i++) {
163 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4, 163 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_STATUS + i * 12, 4,
@@ -165,8 +165,9 @@ void dw_handle_msi_irq(struct pcie_port *pp)
165 if (val) { 165 if (val) {
166 pos = 0; 166 pos = 0;
167 while ((pos = find_next_bit(&val, 32, pos)) != 32) { 167 while ((pos = find_next_bit(&val, 32, pos)) != 32) {
168 generic_handle_irq(pp->msi_irq_start 168 irq = irq_find_mapping(pp->irq_domain,
169 + (i * 32) + pos); 169 i * 32 + pos);
170 generic_handle_irq(irq);
170 pos++; 171 pos++;
171 } 172 }
172 } 173 }
@@ -237,9 +238,8 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
237 } 238 }
238 } 239 }
239 240
240 irq = (pp->msi_irq_start + pos0); 241 irq = irq_find_mapping(pp->irq_domain, pos0);
241 242 if (!irq)
242 if ((irq + no_irqs) > (pp->msi_irq_start + MAX_MSI_IRQS-1))
243 goto no_valid_irq; 243 goto no_valid_irq;
244 244
245 i = 0; 245 i = 0;
@@ -270,6 +270,7 @@ static void clear_irq(unsigned int irq)
270 struct irq_desc *desc; 270 struct irq_desc *desc;
271 struct msi_desc *msi; 271 struct msi_desc *msi;
272 struct pcie_port *pp; 272 struct pcie_port *pp;
273 struct irq_data *data = irq_get_irq_data(irq);
273 274
274 /* get the port structure */ 275 /* get the port structure */
275 desc = irq_to_desc(irq); 276 desc = irq_to_desc(irq);
@@ -280,7 +281,7 @@ static void clear_irq(unsigned int irq)
280 return; 281 return;
281 } 282 }
282 283
283 pos = irq - pp->msi_irq_start; 284 pos = data->hwirq;
284 285
285 irq_free_desc(irq); 286 irq_free_desc(irq);
286 287
@@ -371,8 +372,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
371 struct of_pci_range range; 372 struct of_pci_range range;
372 struct of_pci_range_parser parser; 373 struct of_pci_range_parser parser;
373 u32 val; 374 u32 val;
374 375 int i;
375 struct irq_domain *irq_domain;
376 376
377 if (of_pci_range_parser_init(&parser, np)) { 377 if (of_pci_range_parser_init(&parser, np)) {
378 dev_err(pp->dev, "missing ranges property\n"); 378 dev_err(pp->dev, "missing ranges property\n");
@@ -441,15 +441,16 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
441 } 441 }
442 442
443 if (IS_ENABLED(CONFIG_PCI_MSI)) { 443 if (IS_ENABLED(CONFIG_PCI_MSI)) {
444 irq_domain = irq_domain_add_linear(pp->dev->of_node, 444 pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
445 MAX_MSI_IRQS, &msi_domain_ops, 445 MAX_MSI_IRQS, &msi_domain_ops,
446 &dw_pcie_msi_chip); 446 &dw_pcie_msi_chip);
447 if (!irq_domain) { 447 if (!pp->irq_domain) {
448 dev_err(pp->dev, "irq domain init failed\n"); 448 dev_err(pp->dev, "irq domain init failed\n");
449 return -ENXIO; 449 return -ENXIO;
450 } 450 }
451 451
452 pp->msi_irq_start = irq_find_mapping(irq_domain, 0); 452 for (i = 0; i < MAX_MSI_IRQS; i++)
453 irq_create_mapping(pp->irq_domain, i);
453 } 454 }
454 455
455 if (pp->ops->host_init) 456 if (pp->ops->host_init)
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index 890c2ced1abd..c15379be2372 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -50,7 +50,7 @@ struct pcie_port {
50 u32 lanes; 50 u32 lanes;
51 struct pcie_host_ops *ops; 51 struct pcie_host_ops *ops;
52 int msi_irq; 52 int msi_irq;
53 int msi_irq_start; 53 struct irq_domain *irq_domain;
54 unsigned long msi_data; 54 unsigned long msi_data;
55 DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS); 55 DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
56}; 56};