aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorLucas Stach <l.stach@pengutronix.de>2014-09-30 12:36:26 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-09-30 17:08:58 -0400
commit91f8ae823f2be0ea3863360dc9327ab573a8f183 (patch)
tree2ace0688824fdce7708d7ba3fc3bbefa07eed76a /drivers/pci
parent24832b4de315ad00e5430a53772750dfcf18514d (diff)
PCI: designware: Setup and clear exactly one MSI at a time
The setup_irq function is supposed to set up exactly one MSI IRQ. Multiple IRQ setup is handled differently, to respect the choices made by the upper layers. Also only clear one MSI IRQ at a time; the PCI core will call into this function multiple times if it has to tear down more than one MSI IRQ. Signed-off-by: Lucas Stach <l.stach@pengutronix.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Pratyush Anand <pratyush.anand@st.com> Acked-by: Jingoo Han <jg1.han@samsung.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/host/pcie-designware.c47
1 files changed, 7 insertions, 40 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index 34e736601259..339296cbc823 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -313,54 +313,17 @@ no_valid_irq:
313 return -ENOSPC; 313 return -ENOSPC;
314} 314}
315 315
316static void clear_irq(unsigned int irq)
317{
318 unsigned int pos, nvec;
319 struct msi_desc *msi;
320 struct pcie_port *pp;
321 struct irq_data *data = irq_get_irq_data(irq);
322
323 /* get the port structure */
324 msi = irq_data_get_msi(data);
325 pp = sys_to_pcie(msi->dev->bus->sysdata);
326
327 /* undo what was done in assign_irq */
328 pos = data->hwirq;
329 nvec = 1 << msi->msi_attrib.multiple;
330
331 clear_irq_range(pp, irq, nvec, pos);
332
333 /* all irqs cleared; reset attributes */
334 msi->irq = 0;
335 msi->msi_attrib.multiple = 0;
336}
337
338static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, 316static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
339 struct msi_desc *desc) 317 struct msi_desc *desc)
340{ 318{
341 int irq, pos, msgvec; 319 int irq, pos;
342 u16 msg_ctr;
343 struct msi_msg msg; 320 struct msi_msg msg;
344 struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata); 321 struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
345 322
346 pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS, 323 irq = assign_irq(1, desc, &pos);
347 &msg_ctr);
348 msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
349 if (msgvec == 0)
350 msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
351 if (msgvec > 5)
352 msgvec = 0;
353
354 irq = assign_irq((1 << msgvec), desc, &pos);
355 if (irq < 0) 324 if (irq < 0)
356 return irq; 325 return irq;
357 326
358 /*
359 * write_msi_msg() will update PCI_MSI_FLAGS so there is
360 * no need to explicitly call pci_write_config_word().
361 */
362 desc->msi_attrib.multiple = msgvec;
363
364 if (pp->ops->get_msi_addr) 327 if (pp->ops->get_msi_addr)
365 msg.address_lo = pp->ops->get_msi_addr(pp); 328 msg.address_lo = pp->ops->get_msi_addr(pp);
366 else 329 else
@@ -379,7 +342,11 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
379 342
380static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq) 343static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
381{ 344{
382 clear_irq(irq); 345 struct irq_data *data = irq_get_irq_data(irq);
346 struct msi_desc *msi = irq_data_get_msi(data);
347 struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata);
348
349 clear_irq_range(pp, irq, 1, data->hwirq);
383} 350}
384 351
385static struct msi_chip dw_pcie_msi_chip = { 352static struct msi_chip dw_pcie_msi_chip = {