[v2,06/12] iommu: Make dev->fault_param static
Commit Message
The iommu faults, including recoverable faults (IO page faults) and
unrecoverable faults (DMA faults), are generic to all devices. The
iommu faults could possibly be triggered for every device.
The fault_param pointer under struct dev_iommu is the per-device fault
data. Therefore, the fault_param pointer could be static and allocated
during iommu device probe and freed when the device is released.
With this done, the individual iommu drivers that support iopf have no
need to call iommu_[un]register_device_fault_handler() any more.
This will make it easier for the iommu drivers to support iopf, and it
will also make the fault_param allocation and free simpler.
Signed-off-by: Lu Baolu <baolu.lu@linux.intel.com>
---
.../iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c | 13 +------------
drivers/iommu/intel/iommu.c | 18 ++++--------------
drivers/iommu/iommu.c | 14 ++++++++++++++
3 files changed, 19 insertions(+), 26 deletions(-)
Comments
> From: Lu Baolu <baolu.lu@linux.intel.com>
> Sent: Thursday, July 27, 2023 1:49 PM
>
> @@ -4630,7 +4621,6 @@ static int intel_iommu_disable_iopf(struct device
> *dev)
> * fault handler and removing device from iopf queue should never
> * fail.
> */
> - WARN_ON(iommu_unregister_device_fault_handler(dev));
> WARN_ON(iopf_queue_remove_device(iommu->iopf_queue, dev));
the comment should be updated too.
>
> mutex_init(¶m->lock);
> + param->fault_param = kzalloc(sizeof(*param->fault_param),
> GFP_KERNEL);
> + if (!param->fault_param) {
> + kfree(param);
> + return -ENOMEM;
> + }
> + mutex_init(¶m->fault_param->lock);
> + INIT_LIST_HEAD(¶m->fault_param->faults);
let's also move 'partial' from struct iopf_device_param into struct
iommu_fault_param. That logic is not specific to sva.
meanwhile probably iopf_device_param can be renamed to
iopf_sva_param since all the remaining fields are only used by
the sva handler.
current naming (iommu_fault_param vs. iopf_device_param) is a
bit confusing when reading related code.
On 2023/8/3 16:08, Tian, Kevin wrote:
>> From: Lu Baolu <baolu.lu@linux.intel.com>
>> Sent: Thursday, July 27, 2023 1:49 PM
>>
>> @@ -4630,7 +4621,6 @@ static int intel_iommu_disable_iopf(struct device
>> *dev)
>> * fault handler and removing device from iopf queue should never
>> * fail.
>> */
>> - WARN_ON(iommu_unregister_device_fault_handler(dev));
>> WARN_ON(iopf_queue_remove_device(iommu->iopf_queue, dev));
>
> the comment should be updated too.
Ack.
>
>>
>> mutex_init(¶m->lock);
>> + param->fault_param = kzalloc(sizeof(*param->fault_param),
>> GFP_KERNEL);
>> + if (!param->fault_param) {
>> + kfree(param);
>> + return -ENOMEM;
>> + }
>> + mutex_init(¶m->fault_param->lock);
>> + INIT_LIST_HEAD(¶m->fault_param->faults);
>
> let's also move 'partial' from struct iopf_device_param into struct
> iommu_fault_param. That logic is not specific to sva.
>
> meanwhile probably iopf_device_param can be renamed to
> iopf_sva_param since all the remaining fields are only used by
> the sva handler.
>
> current naming (iommu_fault_param vs. iopf_device_param) is a
> bit confusing when reading related code.
My understanding is that iommu_fault_param is for all kinds of iommu
faults. Currently they probably include recoverable IO page faults or
unrecoverable DMA faults.
While, iopf_device_param is for the recoverable IO page faults. I agree
that this naming is not specific and even confusing. Perhaps renaming it
to something like iommu_iopf_param?
Best regards,
baolu
> From: Baolu Lu <baolu.lu@linux.intel.com>
> Sent: Friday, August 4, 2023 11:17 AM
>
> On 2023/8/3 16:08, Tian, Kevin wrote:
> >> From: Lu Baolu <baolu.lu@linux.intel.com>
> >> Sent: Thursday, July 27, 2023 1:49 PM
> >>
> >>
> >> mutex_init(¶m->lock);
> >> + param->fault_param = kzalloc(sizeof(*param->fault_param),
> >> GFP_KERNEL);
> >> + if (!param->fault_param) {
> >> + kfree(param);
> >> + return -ENOMEM;
> >> + }
> >> + mutex_init(¶m->fault_param->lock);
> >> + INIT_LIST_HEAD(¶m->fault_param->faults);
> >
> > let's also move 'partial' from struct iopf_device_param into struct
> > iommu_fault_param. That logic is not specific to sva.
> >
> > meanwhile probably iopf_device_param can be renamed to
> > iopf_sva_param since all the remaining fields are only used by
> > the sva handler.
> >
> > current naming (iommu_fault_param vs. iopf_device_param) is a
> > bit confusing when reading related code.
>
> My understanding is that iommu_fault_param is for all kinds of iommu
> faults. Currently they probably include recoverable IO page faults or
> unrecoverable DMA faults.
>
> While, iopf_device_param is for the recoverable IO page faults. I agree
> that this naming is not specific and even confusing. Perhaps renaming it
> to something like iommu_iopf_param?
>
or just iopf_param...
On 8/4/23 11:56 AM, Tian, Kevin wrote:
>> From: Baolu Lu <baolu.lu@linux.intel.com>
>> Sent: Friday, August 4, 2023 11:17 AM
>>
>> On 2023/8/3 16:08, Tian, Kevin wrote:
>>>> From: Lu Baolu <baolu.lu@linux.intel.com>
>>>> Sent: Thursday, July 27, 2023 1:49 PM
>>>>
>>>>
>>>> mutex_init(¶m->lock);
>>>> + param->fault_param = kzalloc(sizeof(*param->fault_param),
>>>> GFP_KERNEL);
>>>> + if (!param->fault_param) {
>>>> + kfree(param);
>>>> + return -ENOMEM;
>>>> + }
>>>> + mutex_init(¶m->fault_param->lock);
>>>> + INIT_LIST_HEAD(¶m->fault_param->faults);
>>>
>>> let's also move 'partial' from struct iopf_device_param into struct
>>> iommu_fault_param. That logic is not specific to sva.
>>>
>>> meanwhile probably iopf_device_param can be renamed to
>>> iopf_sva_param since all the remaining fields are only used by
>>> the sva handler.
>>>
>>> current naming (iommu_fault_param vs. iopf_device_param) is a
>>> bit confusing when reading related code.
>>
>> My understanding is that iommu_fault_param is for all kinds of iommu
>> faults. Currently they probably include recoverable IO page faults or
>> unrecoverable DMA faults.
>>
>> While, iopf_device_param is for the recoverable IO page faults. I agree
>> that this naming is not specific and even confusing. Perhaps renaming it
>> to something like iommu_iopf_param?
>>
>
> or just iopf_param.
Okay.
Best regards,
baolu
On Thu, Jul 27, 2023 at 01:48:31PM +0800, Lu Baolu wrote:
> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> index 4ba3bb692993..3e4ff984aa85 100644
> --- a/drivers/iommu/iommu.c
> +++ b/drivers/iommu/iommu.c
> @@ -302,7 +302,15 @@ static int dev_iommu_get(struct device *dev)
> return -ENOMEM;
>
> mutex_init(¶m->lock);
> + param->fault_param = kzalloc(sizeof(*param->fault_param), GFP_KERNEL);
> + if (!param->fault_param) {
> + kfree(param);
> + return -ENOMEM;
> + }
> + mutex_init(¶m->fault_param->lock);
> + INIT_LIST_HEAD(¶m->fault_param->faults);
> dev->iommu = param;
This allocation seems pointless?
If we always allocate the fault param then just don't make it a
pointer in the first place.
The appeal of allocation would be to save a few bytes in the common
case that the driver doesn't support faulting.
Which means the driver needs to make some call to enable faulting for
a device. In this case I'd continue to lazy free on release like this
patch does.
Jason
On Thu, Aug 10, 2023 at 03:20:07PM -0300, Jason Gunthorpe wrote:
> On Thu, Jul 27, 2023 at 01:48:31PM +0800, Lu Baolu wrote:
> > diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
> > index 4ba3bb692993..3e4ff984aa85 100644
> > --- a/drivers/iommu/iommu.c
> > +++ b/drivers/iommu/iommu.c
> > @@ -302,7 +302,15 @@ static int dev_iommu_get(struct device *dev)
> > return -ENOMEM;
> >
> > mutex_init(¶m->lock);
> > + param->fault_param = kzalloc(sizeof(*param->fault_param), GFP_KERNEL);
> > + if (!param->fault_param) {
> > + kfree(param);
> > + return -ENOMEM;
> > + }
> > + mutex_init(¶m->fault_param->lock);
> > + INIT_LIST_HEAD(¶m->fault_param->faults);
> > dev->iommu = param;
>
> This allocation seems pointless?
>
> If we always allocate the fault param then just don't make it a
> pointer in the first place.
>
> The appeal of allocation would be to save a few bytes in the common
> case that the driver doesn't support faulting.
>
> Which means the driver needs to make some call to enable faulting for
> a device. In this case I'd continue to lazy free on release like this
> patch does.
For instance allocate the fault_param in iopf_queue_add_device() which
is the only thing that needs it.
Actually probably just merge struct iopf_device_param and
iommu_fault_param ?
When you call iopf_queue_add_device() it enables page faulting mode,
does 1 additional allocation for all additional required per-device
memory and thats it.
Jason
On 2023/8/11 2:46, Jason Gunthorpe wrote:
> On Thu, Aug 10, 2023 at 03:20:07PM -0300, Jason Gunthorpe wrote:
>> On Thu, Jul 27, 2023 at 01:48:31PM +0800, Lu Baolu wrote:
>>> diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
>>> index 4ba3bb692993..3e4ff984aa85 100644
>>> --- a/drivers/iommu/iommu.c
>>> +++ b/drivers/iommu/iommu.c
>>> @@ -302,7 +302,15 @@ static int dev_iommu_get(struct device *dev)
>>> return -ENOMEM;
>>>
>>> mutex_init(¶m->lock);
>>> + param->fault_param = kzalloc(sizeof(*param->fault_param), GFP_KERNEL);
>>> + if (!param->fault_param) {
>>> + kfree(param);
>>> + return -ENOMEM;
>>> + }
>>> + mutex_init(¶m->fault_param->lock);
>>> + INIT_LIST_HEAD(¶m->fault_param->faults);
>>> dev->iommu = param;
>> This allocation seems pointless?
>>
>> If we always allocate the fault param then just don't make it a
>> pointer in the first place.
>>
>> The appeal of allocation would be to save a few bytes in the common
>> case that the driver doesn't support faulting.
>>
>> Which means the driver needs to make some call to enable faulting for
>> a device. In this case I'd continue to lazy free on release like this
>> patch does.
> For instance allocate the fault_param in iopf_queue_add_device() which
> is the only thing that needs it.
>
> Actually probably just merge struct iopf_device_param and
> iommu_fault_param ?
>
> When you call iopf_queue_add_device() it enables page faulting mode,
> does 1 additional allocation for all additional required per-device
> memory and thats it.
Agreed.
I originally kept the iommu_fault_param structure because I thought it
could also be used to store temporary data for unrecoverable faults,
just like the iopf_device_param structure is used for iopf. However, I
am not sure whether we actually need any temporary data for
unrecoverable fault forwarding, which doesn't require any response.
So, it's better to do like you suggested. It's cleaner and simpler.
Best regards,
baolu
@@ -437,7 +437,6 @@ bool arm_smmu_master_sva_enabled(struct arm_smmu_master *master)
static int arm_smmu_master_sva_enable_iopf(struct arm_smmu_master *master)
{
- int ret;
struct device *dev = master->dev;
/*
@@ -450,16 +449,7 @@ static int arm_smmu_master_sva_enable_iopf(struct arm_smmu_master *master)
if (!master->iopf_enabled)
return -EINVAL;
- ret = iopf_queue_add_device(master->smmu->evtq.iopf, dev);
- if (ret)
- return ret;
-
- ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
- if (ret) {
- iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
- return ret;
- }
- return 0;
+ return iopf_queue_add_device(master->smmu->evtq.iopf, dev);
}
static void arm_smmu_master_sva_disable_iopf(struct arm_smmu_master *master)
@@ -469,7 +459,6 @@ static void arm_smmu_master_sva_disable_iopf(struct arm_smmu_master *master)
if (!master->iopf_enabled)
return;
- iommu_unregister_device_fault_handler(dev);
iopf_queue_remove_device(master->smmu->evtq.iopf, dev);
}
@@ -4587,23 +4587,14 @@ static int intel_iommu_enable_iopf(struct device *dev)
if (ret)
return ret;
- ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev);
- if (ret)
- goto iopf_remove_device;
-
ret = pci_enable_pri(pdev, PRQ_DEPTH);
- if (ret)
- goto iopf_unregister_handler;
+ if (ret) {
+ iopf_queue_remove_device(iommu->iopf_queue, dev);
+ return ret;
+ }
info->pri_enabled = 1;
return 0;
-
-iopf_unregister_handler:
- iommu_unregister_device_fault_handler(dev);
-iopf_remove_device:
- iopf_queue_remove_device(iommu->iopf_queue, dev);
-
- return ret;
}
static int intel_iommu_disable_iopf(struct device *dev)
@@ -4630,7 +4621,6 @@ static int intel_iommu_disable_iopf(struct device *dev)
* fault handler and removing device from iopf queue should never
* fail.
*/
- WARN_ON(iommu_unregister_device_fault_handler(dev));
WARN_ON(iopf_queue_remove_device(iommu->iopf_queue, dev));
return 0;
@@ -302,7 +302,15 @@ static int dev_iommu_get(struct device *dev)
return -ENOMEM;
mutex_init(¶m->lock);
+ param->fault_param = kzalloc(sizeof(*param->fault_param), GFP_KERNEL);
+ if (!param->fault_param) {
+ kfree(param);
+ return -ENOMEM;
+ }
+ mutex_init(¶m->fault_param->lock);
+ INIT_LIST_HEAD(¶m->fault_param->faults);
dev->iommu = param;
+
return 0;
}
@@ -315,6 +323,12 @@ static void dev_iommu_free(struct device *dev)
fwnode_handle_put(param->fwspec->iommu_fwnode);
kfree(param->fwspec);
}
+ /*
+ * All pending faults should have been drained before
+ * device release.
+ */
+ WARN_ON_ONCE(!list_empty(¶m->fault_param->faults));
+ kfree(param->fault_param);
kfree(param);
}