aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/perf/arm_smmuv3_pmu.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/drivers/perf/arm_smmuv3_pmu.c b/drivers/perf/arm_smmuv3_pmu.c
index a6d2e3ce94df..a4f4b488a2de 100644
--- a/drivers/perf/arm_smmuv3_pmu.c
+++ b/drivers/perf/arm_smmuv3_pmu.c
@@ -67,6 +67,7 @@
67#define SMMU_PMCG_OVSSET0 0xCC0 67#define SMMU_PMCG_OVSSET0 0xCC0
68#define SMMU_PMCG_CFGR 0xE00 68#define SMMU_PMCG_CFGR 0xE00
69#define SMMU_PMCG_CFGR_SID_FILTER_TYPE BIT(23) 69#define SMMU_PMCG_CFGR_SID_FILTER_TYPE BIT(23)
70#define SMMU_PMCG_CFGR_MSI BIT(21)
70#define SMMU_PMCG_CFGR_RELOC_CTRS BIT(20) 71#define SMMU_PMCG_CFGR_RELOC_CTRS BIT(20)
71#define SMMU_PMCG_CFGR_SIZE GENMASK(13, 8) 72#define SMMU_PMCG_CFGR_SIZE GENMASK(13, 8)
72#define SMMU_PMCG_CFGR_NCTR GENMASK(5, 0) 73#define SMMU_PMCG_CFGR_NCTR GENMASK(5, 0)
@@ -77,6 +78,12 @@
77#define SMMU_PMCG_IRQ_CTRL 0xE50 78#define SMMU_PMCG_IRQ_CTRL 0xE50
78#define SMMU_PMCG_IRQ_CTRL_IRQEN BIT(0) 79#define SMMU_PMCG_IRQ_CTRL_IRQEN BIT(0)
79#define SMMU_PMCG_IRQ_CFG0 0xE58 80#define SMMU_PMCG_IRQ_CFG0 0xE58
81#define SMMU_PMCG_IRQ_CFG1 0xE60
82#define SMMU_PMCG_IRQ_CFG2 0xE64
83
84/* MSI config fields */
85#define MSI_CFG0_ADDR_MASK GENMASK_ULL(51, 2)
86#define MSI_CFG2_MEMATTR_DEVICE_nGnRE 0x1
80 87
81#define SMMU_PMCG_DEFAULT_FILTER_SPAN 1 88#define SMMU_PMCG_DEFAULT_FILTER_SPAN 1
82#define SMMU_PMCG_DEFAULT_FILTER_SID GENMASK(31, 0) 89#define SMMU_PMCG_DEFAULT_FILTER_SID GENMASK(31, 0)
@@ -580,11 +587,62 @@ static irqreturn_t smmu_pmu_handle_irq(int irq_num, void *data)
580 return IRQ_HANDLED; 587 return IRQ_HANDLED;
581} 588}
582 589
590static void smmu_pmu_free_msis(void *data)
591{
592 struct device *dev = data;
593
594 platform_msi_domain_free_irqs(dev);
595}
596
597static void smmu_pmu_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg)
598{
599 phys_addr_t doorbell;
600 struct device *dev = msi_desc_to_dev(desc);
601 struct smmu_pmu *pmu = dev_get_drvdata(dev);
602
603 doorbell = (((u64)msg->address_hi) << 32) | msg->address_lo;
604 doorbell &= MSI_CFG0_ADDR_MASK;
605
606 writeq_relaxed(doorbell, pmu->reg_base + SMMU_PMCG_IRQ_CFG0);
607 writel_relaxed(msg->data, pmu->reg_base + SMMU_PMCG_IRQ_CFG1);
608 writel_relaxed(MSI_CFG2_MEMATTR_DEVICE_nGnRE,
609 pmu->reg_base + SMMU_PMCG_IRQ_CFG2);
610}
611
612static void smmu_pmu_setup_msi(struct smmu_pmu *pmu)
613{
614 struct msi_desc *desc;
615 struct device *dev = pmu->dev;
616 int ret;
617
618 /* Clear MSI address reg */
619 writeq_relaxed(0, pmu->reg_base + SMMU_PMCG_IRQ_CFG0);
620
621 /* MSI supported or not */
622 if (!(readl(pmu->reg_base + SMMU_PMCG_CFGR) & SMMU_PMCG_CFGR_MSI))
623 return;
624
625 ret = platform_msi_domain_alloc_irqs(dev, 1, smmu_pmu_write_msi_msg);
626 if (ret) {
627 dev_warn(dev, "failed to allocate MSIs\n");
628 return;
629 }
630
631 desc = first_msi_entry(dev);
632 if (desc)
633 pmu->irq = desc->irq;
634
635 /* Add callback to free MSIs on teardown */
636 devm_add_action(dev, smmu_pmu_free_msis, dev);
637}
638
583static int smmu_pmu_setup_irq(struct smmu_pmu *pmu) 639static int smmu_pmu_setup_irq(struct smmu_pmu *pmu)
584{ 640{
585 unsigned long flags = IRQF_NOBALANCING | IRQF_SHARED | IRQF_NO_THREAD; 641 unsigned long flags = IRQF_NOBALANCING | IRQF_SHARED | IRQF_NO_THREAD;
586 int irq, ret = -ENXIO; 642 int irq, ret = -ENXIO;
587 643
644 smmu_pmu_setup_msi(pmu);
645
588 irq = pmu->irq; 646 irq = pmu->irq;
589 if (irq) 647 if (irq)
590 ret = devm_request_irq(pmu->dev, irq, smmu_pmu_handle_irq, 648 ret = devm_request_irq(pmu->dev, irq, smmu_pmu_handle_irq,