From: Robin Murphy <robin.murphy@arm.com>
To: Zong Li <zong.li@sifive.com>
Cc: joro@8bytes.org, will@kernel.org, tjeznach@rivosinc.com,
paul.walmsley@sifive.com, palmer@dabbelt.com,
aou@eecs.berkeley.edu, luxu.kernel@bytedance.com,
linux-kernel@vger.kernel.org, iommu@lists.linux.dev,
linux-riscv@lists.infradead.org
Subject: Re: [PATCH 2/2] iommu/riscv: support HPM and interrupt handling
Date: Fri, 17 Jan 2025 12:45:10 +0000 [thread overview]
Message-ID: <b0dadc40-638e-4f14-8a5c-70c306bc4650@arm.com> (raw)
In-Reply-To: <CANXhq0oDv0b_S=6EmETAUkjQxo3Zz5fZ-yeP-9hHSMW9Ak5=sg@mail.gmail.com>
On 2025-01-17 2:46 am, Zong Li wrote:
> On Thu, Jan 16, 2025 at 5:56 AM Robin Murphy <robin.murphy@arm.com> wrote:
>>
>> On 2025-01-15 3:03 am, Zong Li wrote:
>>> Initialize the PMU and uninitialize it when driver is removed.
>>> Interrupt handling is also implemented, and the handler needs
>>> to be a primary handler instead of a threaded function because
>>> pt_regs is empty when threading the IRQ. However, pt_regs is
>>> required by perf_event_overflow.
>>>
>>> Signed-off-by: Zong Li <zong.li@sifive.com>
>>> Tested-by: Xu Lu <luxu.kernel@bytedance.com>
>>> ---
>>> drivers/iommu/riscv/iommu.c | 65 +++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 65 insertions(+)
>>>
>>> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
>>> index 8a05def774bd..20ae90471484 100644
>>> --- a/drivers/iommu/riscv/iommu.c
>>> +++ b/drivers/iommu/riscv/iommu.c
>>> @@ -552,6 +552,62 @@ static irqreturn_t riscv_iommu_fltq_process(int irq, void *data)
>>> return IRQ_HANDLED;
>>> }
>>>
>>> +/*
>>> + * IOMMU Hardware performance monitor
>>> + */
>>> +
>>> +/* HPM interrupt primary handler */
>>> +static irqreturn_t riscv_iommu_hpm_irq_handler(int irq, void *dev_id)
>>> +{
>>> + struct riscv_iommu_device *iommu = (struct riscv_iommu_device *)dev_id;
>>> +
>>> + /* Clear performance monitoring interrupt pending */
>>> + riscv_iommu_writel(iommu, RISCV_IOMMU_REG_IPSR, RISCV_IOMMU_IPSR_PMIP);
>>> +
>>> + /* Process pmu irq */
>>> + riscv_iommu_pmu_handle_irq(&iommu->pmu);
>>> +
>>> + return IRQ_HANDLED;
>>> +}
>>> +
>>> +/* HPM initialization */
>>> +static int riscv_iommu_hpm_enable(struct riscv_iommu_device *iommu)
>>> +{
>>> + int rc;
>>> +
>>> + if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_HPM))
>>> + return 0;
>>> +
>>> + /*
>>> + * pt_regs is empty when threading the IRQ, but pt_regs is necessary
>>> + * by perf_event_overflow. Use primary handler instead of thread
>>> + * function for PM IRQ.
>>> + *
>>> + * Set the IRQF_ONESHOT flag because this IRQ might be shared with
>>> + * other threaded IRQs by other queues.
>>> + */
>>> + rc = devm_request_irq(iommu->dev,
>>> + iommu->irqs[riscv_iommu_queue_vec(iommu, RISCV_IOMMU_IPSR_PMIP)],
>>> + riscv_iommu_hpm_irq_handler, IRQF_ONESHOT | IRQF_SHARED, NULL, iommu);
>>
>> Hmm, shared interrupts are tricky for PMUs, since perf requires any IRQ
>> handler touching a PMU is running on pmu->cpu, so you have to be very
>> careful about maintaining affinity and not letting anyone else change it
>> behind your back.
>>
>> The other thing is that if it really is shared, at this point you could
>> now be in riscv_iommu_pmu_handle_irq() dereferencing NULL.
>
> Yes, the PMU IRQ line could be shared with the command queue, fault
> queue, and page-request queue.
> Could you please provide more tips on what is meant by "dereferencing
> NULL in riscv_iommu_pmu_handle_irq()"?
> I don't complete understand what needs to be done there.
> Thanks
In general it's not a great idea to register an IRQ handler before the
data passed to that handler is initialised. What is pointed to by
(&iommu->pmu)->reg + RISCV_IOMMU_REG_IOCOUNTOVF if the IRQ fires right
now (and/or if CONFIG_DEBUG_SHIRQ ever gets fixed)? ;)
(OK, it's not *literally* NULL, but hey...)
Thanks,
Robin.
>>
>>> + if (rc)
>>> + return rc;
>>> +
>>> + return riscv_iommu_pmu_init(&iommu->pmu, iommu->reg, dev_name(iommu->dev));
>>> +}
>>> +
>>> +/* HPM uninitialization */
>>> +static void riscv_iommu_hpm_disable(struct riscv_iommu_device *iommu)
>>> +{
>>> + if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_HPM))
>>> + return;
>>> +
>>> + devm_free_irq(iommu->dev,
>>> + iommu->irqs[riscv_iommu_queue_vec(iommu, RISCV_IOMMU_IPSR_PMIP)],
>>> + iommu);
>>> +
>>> + riscv_iommu_pmu_uninit(&iommu->pmu);
>>> +}
>>> +
>>> /* Lookup and initialize device context info structure. */
>>> static struct riscv_iommu_dc *riscv_iommu_get_dc(struct riscv_iommu_device *iommu,
>>> unsigned int devid)
>>> @@ -1596,6 +1652,9 @@ void riscv_iommu_remove(struct riscv_iommu_device *iommu)
>>> riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
>>> riscv_iommu_queue_disable(&iommu->cmdq);
>>> riscv_iommu_queue_disable(&iommu->fltq);
>>> +
>>> + if (iommu->caps & RISCV_IOMMU_CAPABILITIES_HPM)
>>> + riscv_iommu_pmu_uninit(&iommu->pmu);
>>> }
>>>
>>> int riscv_iommu_init(struct riscv_iommu_device *iommu)
>>> @@ -1635,6 +1694,10 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
>>> if (rc)
>>> goto err_queue_disable;
>>>
>>> + rc = riscv_iommu_hpm_enable(iommu);
>>> + if (rc)
>>> + goto err_hpm_disable;
>>> +
>>
>> I would leave this until after the whole IOMMU setup has succeeded. The
>> PMU is not critical to IOMMU operation, so at that point an error is not
>> fatal, it just means you don't get a PMU, thus there shouldn't need to
>> be any cleanup outside riscv_iommu_hpm_enable() itself.
>
> Thanks for pointing this out. PMU failure shouldn't cause the entire
> IOMMU to fail, let me modify it in the next version.
>
>>
>> Thanks,
>> Robin.
>>
>>> rc = iommu_device_sysfs_add(&iommu->iommu, NULL, NULL, "riscv-iommu@%s",
>>> dev_name(iommu->dev));
>>> if (rc) {
>>> @@ -1653,6 +1716,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
>>> err_remove_sysfs:
>>> iommu_device_sysfs_remove(&iommu->iommu);
>>> err_iodir_off:
>>> + riscv_iommu_hpm_disable(iommu);
>>> +err_hpm_disable:
>>> riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
>>> err_queue_disable:
>>> riscv_iommu_queue_disable(&iommu->fltq);
>>
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
next prev parent reply other threads:[~2025-01-17 12:45 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-15 3:03 [PATCH 0/2] RISC-V IOMMU HPM support Zong Li
2025-01-15 3:03 ` [PATCH 1/2] iommu/riscv: add RISC-V IOMMU PMU support Zong Li
2025-01-15 3:45 ` [External] " Xu Lu
2025-01-15 7:48 ` Zong Li
2025-01-15 8:25 ` Xu Lu
2025-01-15 21:32 ` Robin Murphy
2025-01-23 6:56 ` Zong Li
2025-01-23 8:35 ` kernel test robot
2025-01-23 12:16 ` kernel test robot
2025-01-15 3:03 ` [PATCH 2/2] iommu/riscv: support HPM and interrupt handling Zong Li
2025-01-15 9:44 ` Andrew Jones
2025-01-17 2:33 ` Zong Li
2025-01-15 21:56 ` Robin Murphy
2025-01-17 2:46 ` Zong Li
2025-01-17 12:45 ` Robin Murphy [this message]
2025-01-21 8:37 ` Zong Li
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b0dadc40-638e-4f14-8a5c-70c306bc4650@arm.com \
--to=robin.murphy@arm.com \
--cc=aou@eecs.berkeley.edu \
--cc=iommu@lists.linux.dev \
--cc=joro@8bytes.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=luxu.kernel@bytedance.com \
--cc=palmer@dabbelt.com \
--cc=paul.walmsley@sifive.com \
--cc=tjeznach@rivosinc.com \
--cc=will@kernel.org \
--cc=zong.li@sifive.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox