diff options
author | Pratyush Anand <pratyush.anand@st.com> | 2013-10-09 08:32:12 -0400 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2013-10-09 11:14:23 -0400 |
commit | 904d0e7889933fb48d921c998fd1cabb3a9d6635 (patch) | |
tree | 71cddd777f8e69fa16098fc8855174eaf6397809 | |
parent | 73e408508bf6c76d8dc06f044f0e4703a1e27f14 (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.c | 25 | ||||
-rw-r--r-- | drivers/pci/host/pcie-designware.h | 2 |
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 = { | |||
157 | void dw_handle_msi_irq(struct pcie_port *pp) | 157 | void 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 | }; |