diff options
-rw-r--r-- | drivers/pci/host/pcie-rcar.c | 72 |
1 files changed, 70 insertions, 2 deletions
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 45dc3cd74c03..d6e72db29a21 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c | |||
@@ -608,6 +608,18 @@ static int rcar_msi_alloc(struct rcar_msi *chip) | |||
608 | return msi; | 608 | return msi; |
609 | } | 609 | } |
610 | 610 | ||
611 | static int rcar_msi_alloc_region(struct rcar_msi *chip, int no_irqs) | ||
612 | { | ||
613 | int msi; | ||
614 | |||
615 | mutex_lock(&chip->lock); | ||
616 | msi = bitmap_find_free_region(chip->used, INT_PCI_MSI_NR, | ||
617 | order_base_2(no_irqs)); | ||
618 | mutex_unlock(&chip->lock); | ||
619 | |||
620 | return msi; | ||
621 | } | ||
622 | |||
611 | static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq) | 623 | static void rcar_msi_free(struct rcar_msi *chip, unsigned long irq) |
612 | { | 624 | { |
613 | mutex_lock(&chip->lock); | 625 | mutex_lock(&chip->lock); |
@@ -665,7 +677,7 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, | |||
665 | if (hwirq < 0) | 677 | if (hwirq < 0) |
666 | return hwirq; | 678 | return hwirq; |
667 | 679 | ||
668 | irq = irq_create_mapping(msi->domain, hwirq); | 680 | irq = irq_find_mapping(msi->domain, hwirq); |
669 | if (!irq) { | 681 | if (!irq) { |
670 | rcar_msi_free(msi, hwirq); | 682 | rcar_msi_free(msi, hwirq); |
671 | return -EINVAL; | 683 | return -EINVAL; |
@@ -682,6 +694,58 @@ static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev, | |||
682 | return 0; | 694 | return 0; |
683 | } | 695 | } |
684 | 696 | ||
697 | static int rcar_msi_setup_irqs(struct msi_controller *chip, | ||
698 | struct pci_dev *pdev, int nvec, int type) | ||
699 | { | ||
700 | struct rcar_pcie *pcie = container_of(chip, struct rcar_pcie, msi.chip); | ||
701 | struct rcar_msi *msi = to_rcar_msi(chip); | ||
702 | struct msi_desc *desc; | ||
703 | struct msi_msg msg; | ||
704 | unsigned int irq; | ||
705 | int hwirq; | ||
706 | int i; | ||
707 | |||
708 | /* MSI-X interrupts are not supported */ | ||
709 | if (type == PCI_CAP_ID_MSIX) | ||
710 | return -EINVAL; | ||
711 | |||
712 | WARN_ON(!list_is_singular(&pdev->dev.msi_list)); | ||
713 | desc = list_entry(pdev->dev.msi_list.next, struct msi_desc, list); | ||
714 | |||
715 | hwirq = rcar_msi_alloc_region(msi, nvec); | ||
716 | if (hwirq < 0) | ||
717 | return -ENOSPC; | ||
718 | |||
719 | irq = irq_find_mapping(msi->domain, hwirq); | ||
720 | if (!irq) | ||
721 | return -ENOSPC; | ||
722 | |||
723 | for (i = 0; i < nvec; i++) { | ||
724 | /* | ||
725 | * irq_create_mapping() called from rcar_pcie_probe() pre- | ||
726 | * allocates descs, so there is no need to allocate descs here. | ||
727 | * We can therefore assume that if irq_find_mapping() above | ||
728 | * returns non-zero, then the descs are also successfully | ||
729 | * allocated. | ||
730 | */ | ||
731 | if (irq_set_msi_desc_off(irq, i, desc)) { | ||
732 | /* TODO: clear */ | ||
733 | return -EINVAL; | ||
734 | } | ||
735 | } | ||
736 | |||
737 | desc->nvec_used = nvec; | ||
738 | desc->msi_attrib.multiple = order_base_2(nvec); | ||
739 | |||
740 | msg.address_lo = rcar_pci_read_reg(pcie, PCIEMSIALR) & ~MSIFE; | ||
741 | msg.address_hi = rcar_pci_read_reg(pcie, PCIEMSIAUR); | ||
742 | msg.data = hwirq; | ||
743 | |||
744 | pci_write_msi_msg(irq, &msg); | ||
745 | |||
746 | return 0; | ||
747 | } | ||
748 | |||
685 | static void rcar_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) | 749 | static void rcar_msi_teardown_irq(struct msi_controller *chip, unsigned int irq) |
686 | { | 750 | { |
687 | struct rcar_msi *msi = to_rcar_msi(chip); | 751 | struct rcar_msi *msi = to_rcar_msi(chip); |
@@ -716,12 +780,13 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) | |||
716 | struct platform_device *pdev = to_platform_device(pcie->dev); | 780 | struct platform_device *pdev = to_platform_device(pcie->dev); |
717 | struct rcar_msi *msi = &pcie->msi; | 781 | struct rcar_msi *msi = &pcie->msi; |
718 | unsigned long base; | 782 | unsigned long base; |
719 | int err; | 783 | int err, i; |
720 | 784 | ||
721 | mutex_init(&msi->lock); | 785 | mutex_init(&msi->lock); |
722 | 786 | ||
723 | msi->chip.dev = pcie->dev; | 787 | msi->chip.dev = pcie->dev; |
724 | msi->chip.setup_irq = rcar_msi_setup_irq; | 788 | msi->chip.setup_irq = rcar_msi_setup_irq; |
789 | msi->chip.setup_irqs = rcar_msi_setup_irqs; | ||
725 | msi->chip.teardown_irq = rcar_msi_teardown_irq; | 790 | msi->chip.teardown_irq = rcar_msi_teardown_irq; |
726 | 791 | ||
727 | msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR, | 792 | msi->domain = irq_domain_add_linear(pcie->dev->of_node, INT_PCI_MSI_NR, |
@@ -731,6 +796,9 @@ static int rcar_pcie_enable_msi(struct rcar_pcie *pcie) | |||
731 | return -ENOMEM; | 796 | return -ENOMEM; |
732 | } | 797 | } |
733 | 798 | ||
799 | for (i = 0; i < INT_PCI_MSI_NR; i++) | ||
800 | irq_create_mapping(msi->domain, i); | ||
801 | |||
734 | /* Two irqs are for MSI, but they are also used for non-MSI irqs */ | 802 | /* Two irqs are for MSI, but they are also used for non-MSI irqs */ |
735 | err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq, | 803 | err = devm_request_irq(&pdev->dev, msi->irq1, rcar_pcie_msi_irq, |
736 | IRQF_SHARED | IRQF_NO_THREAD, | 804 | IRQF_SHARED | IRQF_NO_THREAD, |