diff options
author | Thomas Petazzoni <thomas.petazzoni@free-electrons.com> | 2017-02-28 09:31:14 -0500 |
---|---|---|
committer | Bjorn Helgaas <bhelgaas@google.com> | 2017-03-14 16:06:33 -0400 |
commit | f21a8b1b68379c116a6d55821f5f6024ce4f3a48 (patch) | |
tree | 7a56cc5a612ec35211ffc96c76a9edaf50735851 | |
parent | 688769f643bfce894f14dc7141bfc6c010f52750 (diff) |
PCI: aardvark: Move to MSI handling using generic MSI support
The MSI support introduced with the initial Aardvark driver was based
on the msi_controller structure and the of_pci_msi_chip_add() /
of_pci_find_msi_chip_by_node() API, which are being deprecated in
favor of the generic MSI support.
Update the Aardvark driver to use the generic MSI support.
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r-- | drivers/pci/host/pci-aardvark.c | 173 |
1 files changed, 67 insertions, 106 deletions
diff --git a/drivers/pci/host/pci-aardvark.c b/drivers/pci/host/pci-aardvark.c index 4fce494271cc..37d0bcd31f8a 100644 --- a/drivers/pci/host/pci-aardvark.c +++ b/drivers/pci/host/pci-aardvark.c | |||
@@ -200,10 +200,12 @@ struct advk_pcie { | |||
200 | struct list_head resources; | 200 | struct list_head resources; |
201 | struct irq_domain *irq_domain; | 201 | struct irq_domain *irq_domain; |
202 | struct irq_chip irq_chip; | 202 | struct irq_chip irq_chip; |
203 | struct msi_controller msi; | ||
204 | struct irq_domain *msi_domain; | 203 | struct irq_domain *msi_domain; |
204 | struct irq_domain *msi_inner_domain; | ||
205 | struct irq_chip msi_bottom_irq_chip; | ||
205 | struct irq_chip msi_irq_chip; | 206 | struct irq_chip msi_irq_chip; |
206 | DECLARE_BITMAP(msi_irq_in_use, MSI_IRQ_NUM); | 207 | struct msi_domain_info msi_domain_info; |
208 | DECLARE_BITMAP(msi_used, MSI_IRQ_NUM); | ||
207 | struct mutex msi_used_lock; | 209 | struct mutex msi_used_lock; |
208 | u16 msi_msg; | 210 | u16 msi_msg; |
209 | int root_bus_nr; | 211 | int root_bus_nr; |
@@ -545,94 +547,64 @@ static struct pci_ops advk_pcie_ops = { | |||
545 | .write = advk_pcie_wr_conf, | 547 | .write = advk_pcie_wr_conf, |
546 | }; | 548 | }; |
547 | 549 | ||
548 | static int advk_pcie_alloc_msi(struct advk_pcie *pcie) | 550 | static void advk_msi_irq_compose_msi_msg(struct irq_data *data, |
551 | struct msi_msg *msg) | ||
549 | { | 552 | { |
550 | int hwirq; | 553 | struct advk_pcie *pcie = irq_data_get_irq_chip_data(data); |
554 | phys_addr_t msi_msg = virt_to_phys(&pcie->msi_msg); | ||
551 | 555 | ||
552 | mutex_lock(&pcie->msi_used_lock); | 556 | msg->address_lo = lower_32_bits(msi_msg); |
553 | hwirq = find_first_zero_bit(pcie->msi_irq_in_use, MSI_IRQ_NUM); | 557 | msg->address_hi = upper_32_bits(msi_msg); |
554 | if (hwirq >= MSI_IRQ_NUM) | 558 | msg->data = data->irq; |
555 | hwirq = -ENOSPC; | ||
556 | else | ||
557 | set_bit(hwirq, pcie->msi_irq_in_use); | ||
558 | mutex_unlock(&pcie->msi_used_lock); | ||
559 | |||
560 | return hwirq; | ||
561 | } | 559 | } |
562 | 560 | ||
563 | static void advk_pcie_free_msi(struct advk_pcie *pcie, int hwirq) | 561 | static int advk_msi_set_affinity(struct irq_data *irq_data, |
562 | const struct cpumask *mask, bool force) | ||
564 | { | 563 | { |
565 | struct device *dev = &pcie->pdev->dev; | 564 | return -EINVAL; |
566 | |||
567 | mutex_lock(&pcie->msi_used_lock); | ||
568 | if (!test_bit(hwirq, pcie->msi_irq_in_use)) | ||
569 | dev_err(dev, "trying to free unused MSI#%d\n", hwirq); | ||
570 | else | ||
571 | clear_bit(hwirq, pcie->msi_irq_in_use); | ||
572 | mutex_unlock(&pcie->msi_used_lock); | ||
573 | } | 565 | } |
574 | 566 | ||
575 | static int advk_pcie_setup_msi_irq(struct msi_controller *chip, | 567 | static int advk_msi_irq_domain_alloc(struct irq_domain *domain, |
576 | struct pci_dev *pdev, | 568 | unsigned int virq, |
577 | struct msi_desc *desc) | 569 | unsigned int nr_irqs, void *args) |
578 | { | 570 | { |
579 | struct advk_pcie *pcie = pdev->bus->sysdata; | 571 | struct advk_pcie *pcie = domain->host_data; |
580 | struct msi_msg msg; | 572 | int hwirq, i; |
581 | int virq, hwirq; | ||
582 | phys_addr_t msi_msg_phys; | ||
583 | |||
584 | /* We support MSI, but not MSI-X */ | ||
585 | if (desc->msi_attrib.is_msix) | ||
586 | return -EINVAL; | ||
587 | |||
588 | hwirq = advk_pcie_alloc_msi(pcie); | ||
589 | if (hwirq < 0) | ||
590 | return hwirq; | ||
591 | 573 | ||
592 | virq = irq_create_mapping(pcie->msi_domain, hwirq); | 574 | mutex_lock(&pcie->msi_used_lock); |
593 | if (!virq) { | 575 | hwirq = bitmap_find_next_zero_area(pcie->msi_used, MSI_IRQ_NUM, |
594 | advk_pcie_free_msi(pcie, hwirq); | 576 | 0, nr_irqs, 0); |
595 | return -EINVAL; | 577 | if (hwirq >= MSI_IRQ_NUM) { |
578 | mutex_unlock(&pcie->msi_used_lock); | ||
579 | return -ENOSPC; | ||
596 | } | 580 | } |
597 | 581 | ||
598 | irq_set_msi_desc(virq, desc); | 582 | bitmap_set(pcie->msi_used, hwirq, nr_irqs); |
599 | 583 | mutex_unlock(&pcie->msi_used_lock); | |
600 | msi_msg_phys = virt_to_phys(&pcie->msi_msg); | ||
601 | |||
602 | msg.address_lo = lower_32_bits(msi_msg_phys); | ||
603 | msg.address_hi = upper_32_bits(msi_msg_phys); | ||
604 | msg.data = virq; | ||
605 | |||
606 | pci_write_msi_msg(virq, &msg); | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | 584 | ||
611 | static void advk_pcie_teardown_msi_irq(struct msi_controller *chip, | 585 | for (i = 0; i < nr_irqs; i++) |
612 | unsigned int irq) | 586 | irq_domain_set_info(domain, virq + i, hwirq + i, |
613 | { | 587 | &pcie->msi_bottom_irq_chip, |
614 | struct irq_data *d = irq_get_irq_data(irq); | 588 | domain->host_data, handle_simple_irq, |
615 | struct msi_desc *msi = irq_data_get_msi_desc(d); | 589 | NULL, NULL); |
616 | struct advk_pcie *pcie = msi_desc_to_pci_sysdata(msi); | ||
617 | unsigned long hwirq = d->hwirq; | ||
618 | 590 | ||
619 | irq_dispose_mapping(irq); | 591 | return hwirq; |
620 | advk_pcie_free_msi(pcie, hwirq); | ||
621 | } | 592 | } |
622 | 593 | ||
623 | static int advk_pcie_msi_map(struct irq_domain *domain, | 594 | static void advk_msi_irq_domain_free(struct irq_domain *domain, |
624 | unsigned int virq, irq_hw_number_t hw) | 595 | unsigned int virq, unsigned int nr_irqs) |
625 | { | 596 | { |
597 | struct irq_data *d = irq_domain_get_irq_data(domain, virq); | ||
626 | struct advk_pcie *pcie = domain->host_data; | 598 | struct advk_pcie *pcie = domain->host_data; |
627 | 599 | ||
628 | irq_set_chip_and_handler(virq, &pcie->msi_irq_chip, | 600 | mutex_lock(&pcie->msi_used_lock); |
629 | handle_simple_irq); | 601 | bitmap_clear(pcie->msi_used, d->hwirq, nr_irqs); |
630 | 602 | mutex_unlock(&pcie->msi_used_lock); | |
631 | return 0; | ||
632 | } | 603 | } |
633 | 604 | ||
634 | static const struct irq_domain_ops advk_pcie_msi_irq_ops = { | 605 | static const struct irq_domain_ops advk_msi_domain_ops = { |
635 | .map = advk_pcie_msi_map, | 606 | .alloc = advk_msi_irq_domain_alloc, |
607 | .free = advk_msi_irq_domain_free, | ||
636 | }; | 608 | }; |
637 | 609 | ||
638 | static void advk_pcie_irq_mask(struct irq_data *d) | 610 | static void advk_pcie_irq_mask(struct irq_data *d) |
@@ -680,30 +652,25 @@ static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie) | |||
680 | { | 652 | { |
681 | struct device *dev = &pcie->pdev->dev; | 653 | struct device *dev = &pcie->pdev->dev; |
682 | struct device_node *node = dev->of_node; | 654 | struct device_node *node = dev->of_node; |
683 | struct irq_chip *msi_irq_chip; | 655 | struct irq_chip *bottom_ic, *msi_ic; |
684 | struct msi_controller *msi; | 656 | struct msi_domain_info *msi_di; |
685 | phys_addr_t msi_msg_phys; | 657 | phys_addr_t msi_msg_phys; |
686 | int ret; | ||
687 | 658 | ||
688 | msi_irq_chip = &pcie->msi_irq_chip; | 659 | mutex_init(&pcie->msi_used_lock); |
689 | 660 | ||
690 | msi_irq_chip->name = devm_kasprintf(dev, GFP_KERNEL, "%s-msi", | 661 | bottom_ic = &pcie->msi_bottom_irq_chip; |
691 | dev_name(dev)); | ||
692 | if (!msi_irq_chip->name) | ||
693 | return -ENOMEM; | ||
694 | 662 | ||
695 | msi_irq_chip->irq_enable = pci_msi_unmask_irq; | 663 | bottom_ic->name = "MSI"; |
696 | msi_irq_chip->irq_disable = pci_msi_mask_irq; | 664 | bottom_ic->irq_compose_msi_msg = advk_msi_irq_compose_msi_msg; |
697 | msi_irq_chip->irq_mask = pci_msi_mask_irq; | 665 | bottom_ic->irq_set_affinity = advk_msi_set_affinity; |
698 | msi_irq_chip->irq_unmask = pci_msi_unmask_irq; | ||
699 | 666 | ||
700 | msi = &pcie->msi; | 667 | msi_ic = &pcie->msi_irq_chip; |
668 | msi_ic->name = "advk-MSI"; | ||
701 | 669 | ||
702 | msi->setup_irq = advk_pcie_setup_msi_irq; | 670 | msi_di = &pcie->msi_domain_info; |
703 | msi->teardown_irq = advk_pcie_teardown_msi_irq; | 671 | msi_di->flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | |
704 | msi->of_node = node; | 672 | MSI_FLAG_MULTI_PCI_MSI; |
705 | 673 | msi_di->chip = msi_ic; | |
706 | mutex_init(&pcie->msi_used_lock); | ||
707 | 674 | ||
708 | msi_msg_phys = virt_to_phys(&pcie->msi_msg); | 675 | msi_msg_phys = virt_to_phys(&pcie->msi_msg); |
709 | 676 | ||
@@ -712,16 +679,18 @@ static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie) | |||
712 | advk_writel(pcie, upper_32_bits(msi_msg_phys), | 679 | advk_writel(pcie, upper_32_bits(msi_msg_phys), |
713 | PCIE_MSI_ADDR_HIGH_REG); | 680 | PCIE_MSI_ADDR_HIGH_REG); |
714 | 681 | ||
715 | pcie->msi_domain = | 682 | pcie->msi_inner_domain = |
716 | irq_domain_add_linear(NULL, MSI_IRQ_NUM, | 683 | irq_domain_add_linear(NULL, MSI_IRQ_NUM, |
717 | &advk_pcie_msi_irq_ops, pcie); | 684 | &advk_msi_domain_ops, pcie); |
718 | if (!pcie->msi_domain) | 685 | if (!pcie->msi_inner_domain) |
719 | return -ENOMEM; | 686 | return -ENOMEM; |
720 | 687 | ||
721 | ret = of_pci_msi_chip_add(msi); | 688 | pcie->msi_domain = |
722 | if (ret < 0) { | 689 | pci_msi_create_irq_domain(of_node_to_fwnode(node), |
723 | irq_domain_remove(pcie->msi_domain); | 690 | msi_di, pcie->msi_inner_domain); |
724 | return ret; | 691 | if (!pcie->msi_domain) { |
692 | irq_domain_remove(pcie->msi_inner_domain); | ||
693 | return -ENOMEM; | ||
725 | } | 694 | } |
726 | 695 | ||
727 | return 0; | 696 | return 0; |
@@ -729,8 +698,8 @@ static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie) | |||
729 | 698 | ||
730 | static void advk_pcie_remove_msi_irq_domain(struct advk_pcie *pcie) | 699 | static void advk_pcie_remove_msi_irq_domain(struct advk_pcie *pcie) |
731 | { | 700 | { |
732 | of_pci_msi_chip_remove(&pcie->msi); | ||
733 | irq_domain_remove(pcie->msi_domain); | 701 | irq_domain_remove(pcie->msi_domain); |
702 | irq_domain_remove(pcie->msi_inner_domain); | ||
734 | } | 703 | } |
735 | 704 | ||
736 | static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) | 705 | static int advk_pcie_init_irq_domain(struct advk_pcie *pcie) |
@@ -917,8 +886,6 @@ static int advk_pcie_probe(struct platform_device *pdev) | |||
917 | struct advk_pcie *pcie; | 886 | struct advk_pcie *pcie; |
918 | struct resource *res; | 887 | struct resource *res; |
919 | struct pci_bus *bus, *child; | 888 | struct pci_bus *bus, *child; |
920 | struct msi_controller *msi; | ||
921 | struct device_node *msi_node; | ||
922 | int ret, irq; | 889 | int ret, irq; |
923 | 890 | ||
924 | pcie = devm_kzalloc(dev, sizeof(struct advk_pcie), GFP_KERNEL); | 891 | pcie = devm_kzalloc(dev, sizeof(struct advk_pcie), GFP_KERNEL); |
@@ -962,14 +929,8 @@ static int advk_pcie_probe(struct platform_device *pdev) | |||
962 | return ret; | 929 | return ret; |
963 | } | 930 | } |
964 | 931 | ||
965 | msi_node = of_parse_phandle(dev->of_node, "msi-parent", 0); | 932 | bus = pci_scan_root_bus(dev, 0, &advk_pcie_ops, |
966 | if (msi_node) | 933 | pcie, &pcie->resources); |
967 | msi = of_pci_find_msi_chip_by_node(msi_node); | ||
968 | else | ||
969 | msi = NULL; | ||
970 | |||
971 | bus = pci_scan_root_bus_msi(dev, 0, &advk_pcie_ops, | ||
972 | pcie, &pcie->resources, &pcie->msi); | ||
973 | if (!bus) { | 934 | if (!bus) { |
974 | advk_pcie_remove_msi_irq_domain(pcie); | 935 | advk_pcie_remove_msi_irq_domain(pcie); |
975 | advk_pcie_remove_irq_domain(pcie); | 936 | advk_pcie_remove_irq_domain(pcie); |